Linux 文件操作

news2024/11/9 10:49:54

文章目录

  • 一、task_struct 和 file 的关系
  • 二、文件操作的系统调用
  • 三、进程默认打开的三个文件
  • 四、文件重定向
  • 五、Linux 下一切皆文件

文件是在磁盘上创建出来的,当我们想进行文件操作时,根据冯诺依曼体系结构,CPU 只和内存交互,为了可以进行文件操作,应将磁盘中的文件先加载到内存中,加载什么呢?至少要加载文件的某些属性

一个用户可能同时会操作多个文件,并且存在多个用户,因此在某一时间内会存在大量的内存文件,为了管理这些内存文件,需要进行先描述,在组织,操作系统为这些内存文件创建了结构体 file,file 中的属性便从磁盘中加载而来,结构体 file 中还可以存在 struct file* 属性,于是便可以将这些 file 结构体链接起来组成某种数据结构,这样对内存文件的管理,也就转换成了对存储数据类型为结构体 file 的某种数据结构的增删查改

进行文件操作时,用户不是自己操作,而是通过进程对文件操作,因此文件操作的本质其实就是进程的 task_struct 对 文件结构体 file 的操作

一、task_struct 和 file 的关系

在这里插入图片描述

task_struct 和 file 的关系中采用了 files_struct 作为中间结构,file_struct 中包含了一个指针数组 fd_array,数组元素存储的是进程加载到内存文件的 file 地址

进程在加载一个文件时,首先操作系统会创建文件结构体 file(如果 file 还未加载到内存),然后会在进程指向的 file_struct 中的 fd_array 中 找到一个下标最小的且没有被使用的位置填充该 file 的地址,进程加载文件完成后,操作系统为了能让进程还可以找到该 file,操作系统给进程提供是 file 地址在 fd_array 中的下标,这个下标我们称之为文件描述符,fd_array 也就称作文件描述符表

二、文件操作的系统调用

  • 打开文件:在进程的文件描述符表中填充对应的 file 地址

系统调用 open,头文件 sys/types.h、sys/stat.h、fcntl.h

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

返回值:成功返回文件描述符,失败返回 -1

参数:

  • pathname:文件路径 + 文件名 + 文件后缀
  • flags:位图,传递多个标志位时,标志位之间用 | 连接
  • mode:新建文件的权限,受进程的 umask 影响

常用的标志位:

  • O_RDONLY:以读的方式打开文件,从文件开始处读取
  • O_WRONLY:以写的方式打开文件,从文件开始处写入,不会清空文件
  • O_APPEND:需要传递以写的方式打开文件,从文件末尾处写入
  • O_TRUNC:需要传递以写的方式打开文件,将文件清空
  • O_CREAT:如果文件不存在,则会创建文件,如果传递这个标志,最好也传递 mode 参数

系统调用 umask,头文件 sys/typse.h、sys/stat.h,设置当前进程的 umask 为 mask,该系统调用总是成功,返回设置之前的 umask

// mode_t 类型就是 unsigned int 的 typedef
mode_t umask(mode_t mask);

系统调用 close/ read / write,头文件 unistd.h

// 关闭文件:在进程的文件描述符表中删除对应的 file 地址
// 成功返回 0,失败返回 -1
int close(int fd);

// 向文件描述符 fd 对应的文件最多读取 count 个字节到 buf 中,文件偏移量会增加文件读取到的字节数
// 成功返回读取到的字节数,0 表示未读取到任何内容,表示已经读取到文件结尾,错误返回 -1
ssize_t read(int fd, void *buf, size_t count);

// 向文件描述符 fd 对应的文件最多写入 count 个 buf 中的字符
// 成功返回写入的字节数,0 表示未写入任何内容,错误返回 -1
ssize_t write(int fd, const void *buf, size_t count);
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    // O_WRONLY 从文件开始处写入,不会清空文件
    // O_APPEND 从文件末尾处写入 
    // O_RDWR   从文件开始处读取
    // int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);
    // int fd = open("log.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);
    int fd = open("log.txt", O_RDONLY);
    if (fd == -1)
    {
        printf("open error : %s\n", strerror(errno));
        exit(1);    
    }

    // R
    char buf[128];
    while (1)
    {
        // int count = read(fd, buf, sizeof(buf) - 1);
        // if (count <= 0) break;

        // buf[count] = '\0';
        // printf("%s", buf);
        
        // 按行读取
        char ch = 1;
        int i = 0;
        for (; read(fd, &ch, 1) != 0 && ch != '\n'; ++i)
            buf[i] = ch; 

        if (i == 0) break;

        buf[i] = '\0';
        printf("%s\n", buf);
        sleep(1);
    }
    
    // W
    // char buf[128];
    // int cnt = 10;
    // while (cnt)
    // {
    //     snprintf(buf, sizeof(buf), "%s, %d\n", "hello world", cnt);
    //     ssize_t ret = write(fd, buf, strlen(buf));
    //     assert(ret != (ssize_t)-1);
    //     (void)ret;
    //     cnt--;
    // }

	// 关闭文件
    close(fd);

    return 0;
}

三、进程默认打开的三个文件

在这里插入图片描述

进程默认打开的三个文件:

  • 0:标准输入,对应于键盘文件
  • 1:标准输出,对应于显示器文件
  • 2:标准错误,对应于显示器文件
#include <stdio.h>
#include <unistd.h>

int main()
{
    // 从键盘文件中读取
    while (1)
    {
        char buf[128];
        char ch;
        int i = 0;
        for (; read(0, &ch, 1) != 0 && ch != '\n'; ++i)
            buf[i] = ch;

        if (i == 0) break;

        buf[i] = '\0';
        printf("从键盘文件中按行读取 : %s\n", buf);
    }

    return 0;
}

在这里插入图片描述

#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main()
{
	// 输出到显示器文件
    int cnt = 5;
    while (cnt)
    {
        char buf[128];
        snprintf(buf, sizeof(buf), "写入到 fd 1 : %s, %d\n", "hello world", cnt);
        write(1, buf, strlen(buf));
        
        snprintf(buf, sizeof(buf), "写入到 fd 2 : %s, %d\n", "hello world", cnt);
        write(2, buf, strlen(buf));

        cnt--;

        printf("\n");
    }
}

在这里插入图片描述

在进程中打开的第一个文件,返回的文件描述符是 3

#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    // 打开文件
    int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);
    assert(fd != -1);

    printf("fd : %d\n", fd);

    // 关闭文件
    close(fd);

    return 0;
}

在这里插入图片描述

四、文件重定向

进程打开新文件时,返回的文件描述符为:文件描述符表中最小并且没有被使用的下标

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    int fd1 = open("file.txt", O_WRONLY | O_CREAT, 0666);
    int fd2 = open("file.txt", O_WRONLY | O_CREAT, 0666);
    int fd3 = open("file.txt", O_WRONLY | O_CREAT, 0666);
    int fd4 = open("file.txt", O_WRONLY | O_CREAT, 0666);
    int fd5 = open("file.txt", O_WRONLY | O_CREAT, 0666);

    printf("%d %d %d %d %d\n", fd1, fd2, fd3, fd4, fd5);

    close(fd3);

    int newFd = open("file.txt", O_WRONLY | O_CREAT, 0666);

    printf("%d\n", newFd);

    close(fd1);
    close(fd2);
    close(fd4);
    close(fd5);
    close(newFd);

	return 0;
}

在这里插入图片描述

重定向的原理:更改进程的文件描述符表中特定下标指向的文件

在这里插入图片描述

实现输出重定向:正常信息输出到 log.normal,异常信息输出到 log.error

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    // 关闭标准输出,打开 log.normal 文件, 此时 log.normal 的文件描述符 为 1
    close(1);
    int normalfd = open("log.normal", O_WRONLY | O_CREAT, 0666);

    // 关闭标准错误,打开 log.error 文件,此时 log.error 的文件描述符为 2 
    close(2);
    int errorfd = open("log.error", O_WRONLY | O_CREAT, 0666);
    
    // 写入到标准输出,即写入到 1 号文件描述符,即写入到 log.normal 文件
    printf("log.normal fd : %d\n", normalfd);
    printf("log.error  fd : %d\n", errorfd);

    // 写入到标准错误,即写入到 2 号文件描述符,即写入到 log.error 文件
    // 以读方式打开一个不存在的文件,模拟错误信息
    int fd = open("abc.txt", O_RDONLY);
    if (fd == -1) perror("open");

	return 0;
}

在这里插入图片描述

系统调用 dup2,头文件 unistd.h

// 将 oldfd 拷贝给 newfd,必要时先关闭 newfd
// 即 fd_arrray[newfd] = fd_array[oldfd]
// 成功返回新的文件描述符,失败返回 -1
int dup2(int oldfd, int newfd);

在这里插入图片描述

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);

    // 重定向 fd_array[1] = fd_array[fd]
    int ret_fd = dup2(fd, 1);

    char buf[128];
    snprintf(buf, sizeof(buf), "dup2 返回值 : %d\n", ret_fd);
    write(1, buf, strlen(buf));
    write(fd, buf, strlen(buf));

    close(fd);
    
    return 0;
}

在这里插入图片描述

五、Linux 下一切皆文件

通过 file 结构体用户可以像文件一样看待 Linux 中的硬件
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/677712.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【裸机开发】Reset 中断服务函数(汇编实现)

目录 一、Reset 中断服务函数的实现步骤 二、汇编实现 Reset 中断服务函数 1、禁止/打开全局中断 2、设置SP指针 3、清除 .bss 段 4、完整 Reset 中断服务函数 一、Reset 中断服务函数的实现步骤 实现 Reset 中断服务函数的基本步骤如下&#xff1a; 设置各个模式下的S…

关联式容器set和map

文章目录 一.容器二.set的介绍1.insert2.lower_bound&&upper_bound3.find和countfindcount 三. multiset四.map最特别的operator[] 四.multimap&#xff0c;因为允许键值冗余&#xff0c;所以它没有operator[]&#xff0c;它的find返回的是中序遍历第一次遇到的节点五.…

ChatGPT办公自动化实战

ChatGPT从入门到精通&#xff0c;一站式掌握办公自动化/爬虫/数据分析和可视化图表制作 全面AI时代就在转角 道路已经铺好了 “局外人”or“先行者” 就在此刻 等你决定 让ChatGPT帮你高效实现职场办公&#xff01;行动起来吧 1、ChatGPT从入门到精通&#xff0c;一站式掌握办…

对象的销毁

析构函数 C 中的类可以定义一个特殊的清理函数 这个特殊的清理函数叫做析构函数析构函数的功能与构造函数相反 定义&#xff1a;~ClassName() 析构函数没有参数也没有返回值类型声明析构函数在对象销毁时自动被调用 析构函数使用初探 #include <stdio.h>class Test …

Threadlocal 必会的9个知识点

1.什么是ThreadLocal&#xff1f;它在多线程环境下有什么用处&#xff1f; ThreadLocal是在多线程环境下提供的一种简单的机制&#xff0c;使得每个线程都能拥有一个独立的变量副本。它避免了线程安全问题&#xff0c;并提高了程序的并发性能。 2.ThreadLocal是如何工作的&am…

规则引擎--规则逻辑形如“1 (2 | 3)“的抽象设计

目录 规则下逻辑表达和条件的抽象表达逻辑的编码和抽象 规则规则下的条件操作符抽象定义规则类规则执行表达式遍历进行操作符计算添加规则下一个具体条件的执行 规则执行完成后得到最后的结果 规则下逻辑表达和条件的抽象 对于任何一个规则&#xff0c;当然包括多个条件&#…

市面上最强PDF:GcPDF 6.1.4 Grapecity -Crack

适用于 .NET 6 的功能丰富的 PDF API 库 完全控制 PDF - 快速生成文档、提高内存效率且无依赖性。 在代码中生成、加载、编辑和保存 PDF 文档 支持多种语言的全文、段落格式和字体 使用新的编辑工具编辑 PDF 中的内容 支持数百种PDF功能 Windows、macOS 和 Linux 完全支持所有…

PhotoShop Beta(爱国版)安装教程-内置AI绘画功能

PS beta版安装教程 Window和Mac版都有&#xff0c;里面内置AI绘画功能 ps Beta版真的太爽了&#xff0c;今天来和大家分享下安装教程。 很多人拿这资料卖5块 9.9 19.9&#xff0c;球友们直接用&#xff0c;建议赶紧装&#xff0c;以免PS更新后&#xff0c;很多pojie程序没法用了…

ChatGPT数据分析与可视化实战

ChatGPT从入门到精通&#xff0c;一站式掌握办公自动化/爬虫/数据分析和可视化图表制作 全面AI时代就在转角 道路已经铺好了 “局外人”or“先行者” 就在此刻 等你决定 让ChatGPT帮你高效实现职场办公&#xff01;行动起来吧1、ChatGPT从入门到精通&#xff0c;一站式掌握办…

docker安装drone

目录 Drone简介docker安装drone创建Drone-server容器创建Drone-runner-docker容器 访问drone-server面板操作 Drone简介 Drone是基于GO语言开发的持续集成&#xff08;Continuous integration&#xff0c;CI&#xff09;引擎&#xff0c;它可以借助Docker容器技术&#xff0c;…

Autosar RTE C/S接口实现及synchronous与asynchronous的区别

文章目录 前言Server接口设计server接口Simulink实现server函数mapping Function生成的代码 Client接口设计Client接口Simulink实现ClientFunction Caller Mapping生成的代码Rte_CallRte_Result 总结 前言 在之前的一篇文章中&#xff0c;介绍了RTE中的S/R接口&#xff0c;也是…

(一)WPF - WPF

一、Window 图形演化 创建用户界面&#xff1a; User32&#xff1a; 该部分为许多元素&#xff08;如窗口、按钮和文本框等&#xff09;提供了熟悉的 Windows 外观。GDI/GDI&#xff1a; 该部分为渲染简单形状、文本以及图像提供了绘图支持&#xff0c;但增加了复杂程度&…

Nginx使用

说明&#xff1a;Nginx是静态资源服务器&#xff0c;可以部署静态资源&#xff0c;并对请求进行策略分发。 下载 第一步&#xff1a;可在官网&#xff08;http://nginx.org/en/download.html&#xff09;下载&#xff0c;建议安装稳定版本&#xff08;Stable version&#xf…

【力扣刷题 | 第十三天】

前言&#xff1a; 今天随机进行练习&#xff0c;题型上不会有什么限制&#xff0c;主要还是练习STL算法。 88. 合并两个有序数组 - 力扣&#xff08;LeetCode&#xff09; 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分…

[RocketMQ] Broker与NameServer的心跳服务源码 (四)

文章目录 1.Broker发送心跳注册请求源码1.1 发送心跳包入口1.2 registerBrokerAll注册broker信息 2.NameServer处理心跳注册请求2.1 处理心跳包入口2.2 NameServer注册broker信息2.2.1 RouteInfoManager介绍2.2.2 registerBroker注册broker 3.NameServer的心跳检测服务3.1 scan…

GIS坐标系统

最新在看GIS的理论知识&#xff0c;坐标系统这块比较抽象&#xff0c;B站上搜到到一个博主的视频&#xff0c;对这块讲解的比较通俗易懂&#xff0c;这里记录一下&#xff1a; 地理坐标系统 地理坐标系统是地球表面空间要素的定位参照系统。地理坐标系统是由经度和维度定义的。…

记录Unity Endless Runner要点

1. Array.IndexOf()查找数组中指定项的索引&#xff0c;如果没找到&#xff0c;就返回-1 2. 如果粒子不是循环播放的&#xff0c;则在粒子播放完毕之后销毁它 if (!m_ParticleSpawned.main.loop)Destroy(m_ParticleSpawned.gameObject, m_ParticleSpawned.main.duration); 3. 检…

普通单目相机标定

前言 这里我们还是以普通相机为例(非鱼眼相机)来进行后续的相关标定操作,再回顾下相机的成像模型如下所示。 已知相机内参(fx,fy,u0,v0),畸变系数[k1,k2,k3,p1,p2],相机外参[R|T]。世界坐标系中点Pw(Xw,Yw,Zw),投影至像素坐标系点p(u,v)的计算过程如下。 1)由世…

操作系统———文件管理

目录 一、初识文件管理1.文件属性2.文件内部数据组织3.文件之间组织4.操作系统向上提供的功能5.文件如何存放在外存6.其他需要由操作系统实现的文件管理功能7.总结 二、文件的逻辑结构1.无结构文件与有结构文件2.有结构文件的逻辑结构2.1顺序文件2.2索引文件2.3索引顺序文件 3.…