1. open
1.1 文件描述符
文件描述符存储在进程PCB块中的一个数据结构内,指向设备文件,通过文件描述符就能操作文件,而打开文件是通过 **int open(const char *pathname, int flags, mode_t mode)**,返回值就是对应文件的描述符,在Linux中,每个进程默认打开三个文件,分别是
STDIN_FILENO:0,标准输入
STDOUT_FILENO:1,标准输出
STDERR_FILENO:2,错误
1.2 flags和mode
- flags : flags指定文件属性,比如非阻塞、追加、只读等,flags只能有一个必选项,就是O_RDONLY,O_WRONLY,O_RDWR中之一,要是多个必选项,则或运算起来的结果会变成不可识别,比如, O_RDONLY | O_WRONLY = 1,结果是RD,会变得不可预测,所以只能有一个必选。
- mode : mode指定文件权限(文件属性为创建时)
flags和mode的宏定义在:/usr/src/linux-headers-4.10.0-35/include/uapi/asm-generic/fcntl.h中S_IRWXU : 所有用户有可写可读可执行 S_IRWXG : 所有组成员有可读可写可执行 S_IROTH : 其他用户只有可读权限 ....
1.3 close
close是关闭文件,即释放对应文件描述符 ,程序结束时一般会自动释放所有的文件描述符,不过在长期运行的程序中,比如服务器程序,一直不关闭的话,是会一直占用文件描述符,可能会导致文件描述符被使用完,所以有些时候需要手动通过close来关闭文件描述符,关闭之后,继续用open打开文件时,返回的文件描述符是最新的文件描述符,可利用这点将输出从终端重定向输出到文件中。
1.4 IO缓冲区
2. read write
2.1 实现cp命令
原理:读取并写入新文件
|
|
2.2 非阻塞读取
read不存在阻塞,只是读取的一个动作,阻塞是在open函数中指定文件的状态,阻塞 或 非阻塞
|
|
3. lseek
3.1 lseek(文件描述符,偏移量,whence);
whence:
1. SEEK_SET
2. SEEK_CUR
3. SEEK_END
1. 通过指针来操作文件
2. 可以通过偏移指针+SEEK_END来扩大文件大小:得有一次写操作才能改变文件
3. 获取文件大小:printf("lseek size = %d\n",lseek(fd,0,SEEK_END));
3.2 实现touch命令
lseek创建空文件时,需要写出操作才能将内容输出,用\0补齐空内容
|
|
4. fcntl
1. 设置文件权限
1.1 文件还未打开:用open来指定文件属性
1.2 文件已经打开:用fcntl来修改文件属性
2. 使用
两次使用fcntl
第一次:获取flags;通过fcntl来获取文件已有的权限(int flags = fcntl(fd,F_GETFL))
第二次:修改flags;通过设置新flags来设置新权限
flags |= O_NONBLOCK;
fcntl(fd,F_SETFL,flags)
4.1 实现非阻塞读取
|
|
5. ioctl
1. 向设备发控制和配置命令,是设备物理的属性,比如串口的波特率等
2. 每个设备的物理特性都不同,需控制也不同
3. 一般设备的物理特性是用read/write函数控制不来,属于out of band,read/write属于in band
|
|
6. 挂起,睡眠
1. 挂起,睡眠都是一种行为,而阻塞,运行是一种状态
2. 挂起:想恢复运行得有人去被动唤醒
3. 睡眠:设置睡眠时间后,自己会主动唤醒
7. 错误处理perror
perror是根据全局变量errno来确定输出错误的内容
linux 系统函数源代码:/usr/src/linux-headers-4.10.0-35/
疑问
1. exit:
exit(1);
exit(0);
exit(-1);各代表了什么意思
2. 结构体有什么用