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系统调用

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: 当文件为链接文件时候,仅返回链接文件信息
    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