Linux程序开发 - 文件操作

AI 摘要: 本文介绍了文件操作相关的内容,包括文件和设备、系统调用、库函数、底层文件访问等。在Linux中,一切皆文件,包括目录文件和普通文件。文件和设备可以通过系统调用进行操作,如打开、读取、写入、关闭等。底层文件访问可以通过文件描述符和系统调用实现。此外,还介绍了库函数的作用和底层系统调用的问题。最后,还提到了执行时间的概念。

文件操作:

  • 文件和设备
  • 系统调用
  • 库函数
  • 底层文件访问
  • 管理文件
  • 标准 IO 库
  • 格式化输入和输出
  • 文件和目录的维护
  • 扫描目录
  • 错误及其处理
  • /proc 文件系统
  • 高级主题:fcntl 和 nmap

Linux 文件结构

在 linux 中,一切皆文件

目录

普通文件=文件本身内容+iNode(节点信息) 目录文件=inodes + 名字 (ls -i)

文件和设备

在 linux 中,硬件设备通常也被映射成文件(/dev/hdc),比较重要的设备文件:

  • /dev/console
  • /dev/tty
  • dev/null (cp /dev/null empty_files)

设备分为字符设备和块设备,区别在于是否一次读取一块内容

系统调用和设备驱动程序

系统调用:linux 提供少量函数,可以直接对文件和设备进行访问和控制,这些函数被称为系统调用,这些也是操作系统本身的接口。

  • open:打开文件或设备
  • read:从打开的文件或设备中读取数据
  • write:向打开的文件或设备中写入数据
  • close:关闭打开的文件或设备
  • ioctl: 把控制信息传递给设备驱动程序(磁带的回绕、串行口的流控等)

系统内核:操作系统的一组设备驱动程序

库函数

直接底层系统调用的问题效率很低:

  • 使用系统调用会影响系统的性能(系统调用过程,Linux 需要从用户代码->内核代码->用户代码这样的执行顺序,需要尽量减少系统调用的次数,一次多读写一些内容,库函数就是解决这块的)
  • 硬件会现在对底层系统调用一次可以读取的数据块大小(磁带一次可以读 10k)

库函数:有函数构成的集合,为了给设备和磁盘文件提供更高层的接口,比如提供输出 Buffer 的标准 I/O 库,极大降低系统调用的开销。

关系:用户空间(用户程序+库函数) <=> 内核空间(系统调用+内核+设备驱动程序)<=> 硬件设备

底层文件访问

运行的程序(process),与之关联的文件描述符,小值整数;通过文件描述符访问打开的文件或设备,文件描述符和系统配置相关,ulmit。 一个程序运行,通常已有三个打开的文件描述符:0:标准输入 1:标准输出 2:标准错误

write 系统调用

系统调用 write:把缓冲区 buf 的前 n 个字节写入文件描述符 fildes 关联的文件中,返回实际写入的字节数,其他返回值(0:为写入 -1:写入失败,错误在 errno 全局变量中) size_t write(int fildes, const void *buf, size_t nbytes)

read 系统调用

系统调用 read:从文件描述符读入 n 字节数据,放入到数据区 buf,返回实际读入的字节数,返回值(0:未读入 -1:读入失败,errno) size_t read(int fildes, void *buf, size_t nbytes);

open 系统调用

1
2
int open(const char *path, int oflags);
int open(const char *path, int oflags, mode_t mode);

调用成功,返回一个可以被 RW 的文件描述符,具有唯一性(两个程序同时打开一个文件,也是得到两个文件描述符);两个同时写,会各写各的,分别接着上次离开的位置继续往下写,数据不会交织在一起,而是会出现彼此覆盖。可以基于锁功能来防止出现冲突。

oflags: 文件访问模式|可选模式的组合

  • O_RDONLY: 只读
  • O_WRONLY:只写
  • O_RDWR:读写

可选模式:

  • O_APPEND:追加数据
  • O_TRUNC:清空内容
  • O_CREAT:按参数 mode 创建文件
  • O_EXCL:排除其他操作,防止同时打开两个文件描述符(原子打开)

访问权限的初始值 open 打开文件时候,如果基于创建文件 O_CREATE,可以传递第三个访问权限的初始化设置(UGO\RWX),这些标识在 sys/stat.h 中定义:

  • S_IRUSR、S_IWUSR、S_IXUSR
  • S_IRGRP、S_IWGRP、S_IXGRP
  • S_IROTH、S_IWOTH、S_IXOTH

属主用户只读、其他用户可执行方式开 a.file open ("a.file", O_CREATE, S_IRUSR|S_IXOTH)

umask 相关:实际打开的文件权限:umask 值求反 & 文件打开的 mode

create 系统调用

等同于`int open(const char *path, O_CREATE|O_WRONLY|O_TRUNC),打开的文件数,与系统 limits.h 相关,有个 OPEN_MAX 参数限制

close 系统调用

终止文件描述符与其对应的文件直接的关联,释放文件描述符,返回值(0:成功,-1:出错)

int close(int fildes);

ioctl 系统调用

提供用于控制设备及其描述符行为和配置底层服务的接口。终端、文件描述符、套接字、磁带机都有它们定义的 ioctl。POSIX 规范只定义了 STREAM 的 ioctl 调用

int ioctl(int fildes, int cmd, ...);

lseek 系统调用

对文件描述符读写指针进行设置,返回值(偏移量,-1:失败)

off_t lseek(int fildes, off_t offset, int whence);

whence 取值,在 sys/types.h 中:

  • SEEK_SET: offset 是绝对位置
  • SEEK_CUR: offset 是相对于当前位置的相对位置
  • SEEK_END: offset 是相对于文件尾部的一个位置

fstat、stat、lstat 系统调用

  • fstat: 返回与文件描述符相关的文件的装填信息,写入到 buf 中
  • stat: 基于文件名查到信息
  • lstat: 当文件为链接文件时候,仅返回链接文件信息
1
2
3
    int fstat(int fildes, struct stat *buf);
    int stat(const char *path, struct stat *buf);
    int lstat(const char *path, struct stat *buf);

stat 结构:

  • st_mode: 文件权限和类型信息
  • st_ino: inode
  • st_dev: 保存文件的设备
  • st_uid、st_gid:文件属主的 uid、gid
  • st_actime: 上次访问时间
  • st_ctime: 创建时间
  • st_mtime: 上次修改时间
  • st_nlink: 文件的硬链接数量

stat 结构还包含 st_mode 相关信息(宏在 sys/sata.h 定义),包括对访问权限、文件类型标志、提供测试特定类型和权限的定义。

dup 和 dup2 系统调用

  • dup: 复制文件描述符,返回一个新的描述符
  • dup2: 明确的复制文件描述符 1 为指定的描述符 2

管道在多进程之间通信,dup 这块很有用

其他内容

执行时间: TIMEFORMAT="" time ./program