日常学习

linux-interface-04

December 30, 2018

The linux programming interface

文件IO 通用的IO模型


文件描述符: 一个非负整数,来指代打开的文件,其中包括: 管道FIFO socket,终端 设备 普通文件

  1. 标准文件描述符:

    文件描述符 用途 名称 stdio
    0 标准输入 STDIN_FILENO stdin
    1 标准输出 STDOUt_FILENO stdout
    2 标准错误 StDERR_FILENO stderr
  2. 主要的系统调用

    • open(pathname, flags, mode) open创建新文件时候, 即 flags 中包含 O_creat 标志,mode制定了文件的访问权限。flags还有许多的可选参数, 包括O_APPEND, O_ASYNC等等。
    • read(fd, buffere, count), read 调用成功返回 实际读取的字节数, 如果遇到文件结束EOF 则返回0, 出席那错误 -1, 一次read 可能返回的 字节数可能小于count, fd为文件时候, 可能是文件靠近结尾,(所以文件尾部时候是不是小于count还是一个0?),fd为其他类型时候, socket, 终端,例如在终端遇到\n read调用就会结束。在有需要注意, C语言, 如果输入缓冲区, buffere 需要一个表示终止的空字符串,需要自己显示添加
    • write(fd, buffer, count), write 为将buffer中的数据写入fd中,error 返回-1, 其他返回写入的字节数, 写入字节数可能小于count (进程资源对文件大小的限制,磁盘满等, 造成部分写),write成功并不能保证已经写入到文件中,而是高速缓冲区,系统会缓存磁盘IO。
    • close(fd) close error -1,success 0, 文件属于有限资源,文件描述符关闭失败可能导致一个进程将资源消耗殆尽。编写长期运行的程序,比如网络服务器显得尤为重要。所以,总是显式的关闭文件描述符。
    • lseek(fd, offset, whence) 改变文件偏移量。文件偏移量是下一个read, write 等的起始点。文件打开指向文件头,read, write 自动调整偏移量. whence 可选参数为 SEEK_SET, SEEK_CUR, SEEK_END, 分表表示offset的基准坐标 为 文件开始头部, 当前偏移量, 文件末尾。 offset 可以为负数 表示,向前偏移多少。调用成功返回移动之后的偏移量。可以使offset为0 来获取当前偏移量。lseek并不适合所有类型的文件,应用与管道, FIFO, socket或者终端,调用将会失败, errno 被设定为ESPIPE.
    • ioctl(fd, request, ….args) 对为纳入标准IO模型的所有设备和文件操作而言,ioctl系统调用是个万金油
    • /proc/PID/fdinfo 目录下,可以获取系统任一进程中文件描述符的相关信息。针对进程中的每一个已打开的文件描述符,该目录下都有对应的文件, 以对应的文件描述符的数值命名,其中文件中的pos为文件偏移量, flags字段 则为一个八进制数, 其格式形如

         pos:  0
         flags: 02
         mnt_id: 9
      

      文件空洞,在 文件结尾+ offset的位置写入数据,会发生什么情况,文件结尾开始到offset 中会产生空洞。文件空洞的特点在于它并不占用磁盘空间,只有当空洞中有数据写入时候,才会分配磁盘空间。 编程角度看读取空洞返回0。空间的存在,造成 文件名义上的大小可能要比其占用的磁盘存储总量要大,当空洞被写入文件时候,内和为其分配存储空间,磁盘可用空间减少。

为所有类型的文件和设备驱动都实现了相同的IO接口, 这保证了IO操作的通用性, 意味着在 无需针对特殊的文件类型特殊编码的情况下, 程序能够操作所有类型的文件。对于已经打开的文件,内核都维护一个文件偏移量。决定了下一次的文件写入起始点。读写都会隐式的改变文件偏移量。使用lseek可以显式的改变偏移量。

未纳入标准IO模型的所有设备操作而言, 使用loctl 系统调用。