Linux 文件I/O

文件如何进行读写?

读书笔记,Linux 系统编程 第二章 文件I/O

Unix 系统主要是通过文件表示的,因此这些章节会设计Unix系统的核心。

在对文件进行读写操作之前,首先需要打开文件。内核会为每个进程维护一个打开文件的列表,该列表就是文件表。文件表示由一些非负整数进行索引,这些非负整数称为文件描述符。列表的每一项是一个打开文件的信息,包括指向该文件索引节点内存拷贝的指针以及关联的元数据,如文件位置指针和访问模式。用户空间和内核空间都使用文件描述符作为唯一cookies,打开文件会返回文件描述符,后续操作都把文件描述符作为基本参数。

文件描述符使用C 语言的int类型表示。每个Linux 进程能开发的文件数是有上限的,文件描述符的范围从0开始,到上限值减一,默认情况下,上限值为1024,也可以对它进行配置,最大为1048576。因为负数不是合法的文件描述符,所以当函数出错不能返回有效的文件描述符时,通常会返回-1。

通常,每个进程至少包含三个文件描述符:0、1、2,除非显式关闭这些描述符。0表示标准输入、1表示标准输出、2表示标准错误。一般而言,stdin是连接到终端的输入设备(通常是键盘),而stdout和stderr是终端的屏幕。用户可以重定向这些文件描述符,甚至可以通过管道把一个程序的输出作为另一个程序的输入。shell正是通过这种方式实现重定向和管道的。

实际上,文件描述符也可以访问设备文件、管道、快速用户空间互斥、先进先出缓冲区和套接字。遵循一切皆文件的理念,几乎任何能够读写的东西都可以通过文件描述符来访问。

默认情况下,子进程会维护一份父进程的文件表副本。在副本中,打开文件列表和其访问模式、当前文件位置以及其他元数据,都和父进程维护的文件表相同,但是存在一点区别:当子进程关闭一个文件时,不会影响到父进程的文件表。虽然一般情况下子进程会自己持有一份文件表,但是子进程和父进程也可以共享文件表。

打开文件

系统调用open
如果系统调用open执行成功,会返回文件描述符,指向路径名 name 所指定的文件。文件位置即文件的起始位置(0),文件打开方式是根据参数flags值来确定。

flags 参数是由一个或多个标志位的按位或组合。支持三种访问模式:O_RDONLY、O_WRONLY 或 O_RDWR,这三种模式分别表示为只读、只写或读写。

flags 参数还可以和以下的值进行按位或运算,修改打开文件的行为;

O_APPEND

文件以追加模式打开。也就是说,在每次写操作之前,将会更新文件位置指针,指向文件末尾。即使有另一个进程也在向该文件写数据,以追加模式打开的进程在最后一次写操作时,还是会更新文件位置指针,指向文件末尾。

O_ASYNC 这个标志位只适用于FIFO、管道、socket和终端,不适用于普通文件。

O_CLOEXEC 执行时关闭 标志位。在执行新的进程时,文件会自动关闭。

O_CREAT 当参数name指定的文件不存在时,内核自动创建。

O_DIRECT 打开文件用于直接I/O

O_DIRECTORY 如果参数name不是目录,open调用会失败。

O_EXCL 当和标志位O_CREAT一起使用时,如果参数name指定的文件已经存在,会导致open调用失败,用于防止创建文件时出现竞争。

O_LARGEFILE 文件偏移使用64位整数表示,可以支持大于2GB文件。

O_NOATIME 在读文件时,不会更新该文件的最后访问时间。可以避免为了更新每个文件的索引节点而导致的大量写操作。
等等…

新建文件所有者

确定新建文件的所有者很简单:文件所有者的uid即创建该文件的进程的有效uid。

creat函数

因为有些参数组合经常使用,因为专门有个系统调用提供这个功能:int creat(const char *name, mode_t mode); 这个函数名creat少了个e。UNIX之父Ken Thompson开玩笑说他在UNIX设计中感到最遗憾的就是漏掉了这个字母。

返回值和错误码

系统调用open和creat在成功时都会返回文件描述符。出错时,返回-1,并把errno设置成相应的错误值。

打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2017-2023 Jacky

所有的相遇,都是久别重逢

支付宝
微信