zoukankan      html  css  js  c++  java
  • APUE 学习笔记 —— 文件I/O

    本章节主要讲了 Linux 系统下的关于文件I/O操作的几个函数:open、read、write、lseek、close 的使用和需要注意的一些细节。接着,又介绍了多进程见如何共享文件。下面开始知识点梳理。

    文件描述符

    对于内核来说,所有打开的文件,都是通过文件描述符来引用。当打开或创建一个新的文件的时候,内核都会向进程返回该文件的文件描述符。文件描述符是什么,可以参考维基百科——文件描述符。UNIX 系统按惯例,会将0与进程的标准输入关联,将1与进程的标准输出关联,将2与进程的标准错误关联。

    open 与 openat 函数的使用

    open 与 openat函数

    • oflag 参数:
      是通过在头文件 <fcntl.h> 中定义的常量中的一个或多个进行 “或”运算构成的。这里不再一一详述每个常量及其含义,感兴趣的小伙伴可以自行去查阅。
    • path 参数:
      是要打开和创建文件的名字。
    • fd 参数:
      fd 把open 和 openat 函数区分开来,具体有三种可能:
      1. 当path是绝对路径时, openat 就相当于是 open;
      2. path制定的是相对路径名称时,fd指出了相对路径名称的在文件系统中的开始位置;
      3. path是相对路径,fd参数具有特殊值 AT_FDCWD。此时,路径名在当前工作目录中获取,openat 函数在操作上与 open 函数类似;
        本节还讲到了 TOCTTOU 思想以及文件名与路径名被截断的问题。

    creat 函数

    creat 函数
    creat函数是以只写的形式来打开一个新的文件的。

    close 函数

    close 函数
    关闭一个文件,会关闭该进程在当前文件上加的所有记录锁。一个进程结束之后,内核会自动关闭其打开的所有文件。

    lseek 函数

    lseek 函数
    lseek 函数仅会将当前的文件偏移量记录到内核中,其不会引起任何 I/O 操作。该偏移量是用来进行下一次读或者写的游标。偏移量的大小可以与文件实际大小不对应。当大于文件当前的实际长度的时候,对该文件的下一次写将加长该文件,且会形成一个空洞。位于文件中但是没有写过的字节都读为0。具体什么是空洞,可以看下百科——文件空洞

    read 函数

    read 函数
    如果 read 成功,则会返回读到的字节数。如果已经读到了文件的末尾,会返回0。

    write 函数

    write 函数
    对于普通文件,通常从当前的偏移量开始;如果在打开文件的时候,指定了 O_APPEND操作,则在每次写操作之前,将文件的偏移量设置在文件的末尾。每次写成功,文件的偏移量都会变化。

    I/O 效率

    大多数文件系统为改善性能,都会增加“预读”技术。当检测到正在进行顺序读取时,系统就试图读入比实际锁要求更多的数据。

    文件共享

    UNIX 系统支持不同进程之间共享打开文件。内核使用三种数据结构用来表示打开文件:
    (1)每个进程在进程记录表中都会有一个记录项,记录项中包含一张打开文件描述符表。有每个文件描述符相关联的是:
    A)文件描述符标志;
    B)指向一个文件表项的指针;
    (2)内核为所有打开文件维持一张文件表,每个文件表项包含:
    A)文件状态标志;
    B)当前文件的偏移量;
    C)指向该文件v节点表项的指针;
    (3)每个打开文件(或设备)都有一个v节点结构。

    打开文件的内核数据结构
    该图显示了一个进程打开多个文件的场景。打开文件描述符表可以存放在用户空间,而非进程表中。
    多个进程打开同一个文件
    该图展示了多个独立的进程打开同一个文件的场景。此场景在读的时候,可以正确的读。但是当涉及到写文件,就会存在了一些不可预料的结果。

    dup 与 dup2 函数

    dup 与 dup2 函数
    两个函数都是用来复制一个现有的文件描述符的。有 dup 返回的新文件描述符一定是当前可用文件描述符中的最小值,对于 dup2,可以用fd2参数指定新描述符的值。如果fd2已经打开,则将其关闭先。若fd=fd2,则dup2返回fd2,而不关闭它。
    dup(1) 后的内核数据结构
    ![dup(1) 后的内核数据结构说明

    sync、fsync、fdatasync 函数

    sync、fsync、fdatasync
    传统的UNIX系统都会在内核中设有缓冲区告诉缓存或页高速缓存,大多数磁盘IO都是通过缓冲区进行。当向文件写数据时,内核通常会先将数据copy到缓冲区中,然后排入队列,晚些时候会写入到磁盘中,这被称为延迟写。当内核需要重用缓冲区来存放其他睡的时候,会将所有数据写入到磁盘中。为了保证磁盘上实际文件系统与缓冲区中内容的一致性,UNIX系统提供了三种函数,如上。它们有什么区别呢?
    三者的区别

    fcntl 函数

    fcntl 函数
    fcntl 函数可以改变已经打开的文件的属性。
    fcntl 函数的5种功能
    fcntl 的返回值与命令有关。如果出错,所有命令都返回-1;成功会返回其他值。
    在修改文件描述符标志或文件状态标志的时候必须谨慎,先要获取现在的标志值,然后再按照期望修改它,最后设置新的标志值。本小节还讲到了调用write时设置同步机制后,对系统性能带来的影响。

    ioctl 函数

    ioctl 函数

  • 相关阅读:
    递归算法详解
    树、森林和二叉树的转换
    C++ 类的静态成员详细讲解
    C++内存分配方式详解——堆、栈、自由存储区、全局/静态存储区和常量存储区
    C++中的static关键字的总结
    C/C++中static关键字详解
    配置文件
    Spring Boot 注释
    使用 Spring Boot 快速构建 Spring 框架应用
    Myeclipse快捷键(二)
  • 原文地址:https://www.cnblogs.com/scharfsinnig/p/10015275.html
Copyright © 2011-2022 走看看