文件操作:
- 文件和设备
- 系统调用
- 库函数
- 底层文件访问
- 管理文件
- 标准 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 系统调用
|
|
调用成功,返回一个可以被 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: 当文件为链接文件时候,仅返回链接文件信息
|
|
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