云计算百科
云计算领域专业知识百科平台

文件描述符

一.linux 打开文件三层结构关系图

文件描述符、打开文件表、inode 关系图

  • 进程文件描述符表(fd_array []) 属于进程 PCB(task_struct)私有,fd 就是数组下标(0/1/2 标准输入输出错误)
  • 系统打开文件表(struct file /file_struct) 全局内核共享,保存读写偏移量、打开标志、引用计数
  • inode 表(inode) 代表磁盘上真实文件,存放文件元信息
  • 其中磁盘文件属性在inode,内容在缓冲区

    1. 文件打开与创建

    通过文件名来打开文件,不存在文件就会创建新的文件。文件都是具有权限的,所以我们需要进行权限的定义。

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

    // 打开已有文件
    int open(const char *pathname, int flags);
    // 创建+打开文件(带权限mode)
    int open(const char *pathname, int flags, mode_t mode);

    第一个参数是文件名,第二个参数是文件的打开方式,第三个参数是文件权限掩码。

    2. 文件关闭

    文件打开后需要及时关闭。

    #include <unistd.h>
    int close(int fd);

    参数是文件描述符,一个进程的整数编号。

    3. 文件写入

    文件需要进行写入操作。

    #include <unistd.h>
    ssize_t write(int fd, const void *buf, size_t count);

    4. 文件再次写入

    4.1 清空写入

    与常规语言不一样,很多是默认清空的,但是这里需要手动清空,要不然会出现覆盖之前的内容。

    第一个参数是文件描述符,第二个参数是需要写入内容缓冲区的起始地址,第三个参数是写入内容的大小。

    使用宏定义映射 O_TRUNC 选项。

    // 再次打开,O_TRUNC 会清空之前文字,重新写
    int fd2 = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
    char buf2[] = "覆盖后的新内容\\n";
    write(fd2, buf2, strlen(buf2));
    close(fd2);
    return 0;

    4.2 结尾追加写入

    使用宏定义映射 O_APPEND 选项。

    // 再次打开追加
    int fd2 = open("log.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);
    write(fd2, "第二条日志\\n", strlen("第二条日志\\n"));
    close(fd2);
    return 0;

    默认写入的是字符串,将整数写入会变成乱码,需要写入时还是需要转化为字符串。

    5. 文件读取

    #include <unistd.h>
    ssize_t read(int fd, void *buf, size_t count);

    fd 参数是文件描述符,一个进程的整数编号。

    6. 文件描述符与标准流

    FILE* 返回值里面封装了文件描述符 fd,例如 stdin、stdout、stderr 这些对应的是 0、1、2。

    7. 重定向

    更改文件描述符的指针指向。

    8. 重定向原理

    文件描述符的分配规则:最小的、没有被使用的,作为新的 fd 给用户。

    int dup2(int oldfd, int newfd);

    作用:让 newfd 指向 oldfd 所关联的文件

  • fd 0 — stdin 标准输入 默认:键盘
  • fd 1 — stdout 标准输出 默认:终端屏幕
  • fd 2 — stderr 标准错误 默认:终端屏幕
  • fd 3 第一个空闲可用的文件描述符 进程新建文件、socket,优先分配最小空闲 fd,0/1/2 被占用,所以新打开文件一般拿到 3。
  • 例子:

    int dup2(3, 1);

    重定向之后可以进行close(oldfd)

    重定向的方式可以是清空重定向,追加重定向,同样的使用O_TRUNC,O_APPEND选项.

    所以重定向就是:打开文件的方式(追加,只读等)+dup2(从哪里到哪里,使用文件描述符)

    • > 标准输出重定向(覆盖)
    • >> 标准输出重定向(追加)
    • < 标准输入重定向

    重定向一定是子进程进行重定向

    重定向细节

    当从标准输出重定向到一个指定文件log.txt时,1和2指向的标准输出和错误都是同一个显示器

    ./out.cc > log.txt //其中的1会省略,即标准输出
    ./out.cc 1 > log.txt //当你使用标准erro时,还是会显示到显示器上面
    ./out.cc 1 > log.normal 2>log.erro

    为什么需要存在一个标准错误:可以通过重定向的能力,把常规消息和错误消息进行分离.

    如果我们不想将标准错误和标准输出的内容进行分开

    ./out 1>log.txt 2>>log.txt //使用追加重定向
    ./out 1>log.txt 2>&1 //让2(标准错误)完全复制 1 号通道。

    9.引用计数

    基础定义

    引用计数:内核给「文件表项」设置一个数字,记录当前有多少个文件描述符指向这同一个文件表。 

    二.理解"一切皆文件"

    我们只要拿到上层的文件描述符就可以通过struct file里面的函数指针(指向函数方法,读写等)来访问不同的硬件(键盘,磁盘等),就是c版本的多态

    1.缓冲区

    缓冲区就像一个快递站,在你忙碌的时候可以将你的包裹暂存,不至于停下手中的工作. 提高各方的效率.

    什么是缓冲区:内存的一段空间

    在c标准库中会有用户级的语言缓冲区,使用库函数(printf,fprintf.fput,fwrite)并不是直接到文件内核缓冲区,当用户(强制刷新,刷新条件满足,进程退出)的时候才会通过(fd+系统调用write等)进入到内核缓冲区,fd可以找到对应文件,在满足条件的时候就可以通过fd找到对应文件写入内核缓冲区再写入到对应的硬件

    一个文件都要有自己的缓冲区,FILE是一个结构体,里面有fd和缓冲区指针

    2.缓冲的几种方式:

    1.立即刷新—无缓冲—写透模式WT

    2.缓冲区满了—全缓冲—缓冲区最满,效率最高!(普通文件)                   

    3.行刷新—行缓冲(显示器)          

    系统调用是有成本的,所以我们通过语言缓冲区来加快效率

    我们只要将数据交给OS,就相当于交给了硬件!数据交给系统,交给硬件—本质全是拷贝!计算机流动的本质:一切皆拷贝

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 文件描述符
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!