目录
文件描述符的实质:一个整型数,一个数组下标(数组的元素指向文件结构体);
文件描述符优先使用可用范围内最小的;
标准输入(stdin)的文件描述符为 0;标准输出(stdout)的文件描述符为 1;标准错误(stderr)的文件描述符为 2;因此其余文件描述符肯定 >= 3;
以下常用函数可通过 man 手册查看其用法;
open():
close():
read();
write();
- int open(const char *pathname, int flags);
- int close(int fd);
- ssize_t read(int fd, void *buf, size_t count);
- ssize_t write(int fd, const void *buf, size_t count);
- #include
- #include
- #include
- #include
- #include
-
- #define BUF_SIZE 1024
-
- int main(int argc, char* argv[]){
-
- int sfd, dfd;
- char* buf[BUF_SIZE];
- int len, ret, pos;
-
- if(argc < 3){
- fprintf(stderr, "Usage...\n");
- exit(1);
- }
- sfd = open(argv[1], O_RDONLY);
- if(sfd < 0){
- perror("open()");
- exit(1);
- }
-
- dfd = open(argv[2], O_WRONLY|O_CREAT, O_TRUNC, 0600);
- if(dfd < 0){
- close(sfd);
- perror("open()");
- exit(1);
- }
- printf("%d %d\n", sfd, dfd); // 3 4
- while(1){
- len = read(sfd, buf, BUF_SIZE);
- if(len < 0 ){
- perror("read()");
- break;
- }
- if(len == 0) break;
-
- pos = 0;
- while(len > 0){
- ret = write(dfd, buf+pos, len);
- if(ret < 0){
- perror("write()");
- exit(1);
- }
- pos += ret;
- len -= ret;
- }
- }
- close(dfd);
- close(sfd);
- exit(0);
- }
标准I/O的吞吐量大(会先把数据放到缓冲区,刷新缓冲区之后才会完成数据的存取),系统I/O的响应速度快(不会把数据放到缓冲区,一次调用就完成一次操作);
标准I/O和系统I/O最好不要混用;
标准I/O和系统I/O的转换函数:fileno() 和 fdopen();
- int mian(){
- putchar('a');
- write(1, "b", 1);
- putchar('a');
- write(1, "b", 1);
- putchar('a');
- write(1, "b", 1);
- }
-
- // 程序会打印:bbbaaa
- // 因为标准I/O打印的 a 会先放到缓冲区中,后面一次完成输出;
原子操作:不可分割的操作;
原子操作的作用:解决竞争与冲突;
- #include
-
- int dup(int oldfd);
- int dup2(int oldfd, int newfd); // 原子操作
-
- // dup 复制(准确来说,将当前文件描述符对于文件的权限共享过来给新的文件描述符了)当前的文件描述符
- // dup 返回一个新的文件描述符,新旧文件描述符共享访问同一个文件
- // dup 返回的新文件描述符一定是当前可用文件描述中的最小数值
-
- // dup2是原子操作,不能被打断,它会关闭旧的文件描述符
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define FNAME "./out"
-
- int main(){
- int fd = open(FNAME, O_WRONLY|O_CREAT|O_TRUNC, 0600);
- if(fd < 0){
- perror("open()");
- exit(1);
- }
- // close(1); // 关闭标准输出
- // dup(fd); // 关闭标准输出后,1成了最小的可用文件描述符,因此dup(fd)后,1和最初的fd共享打开的文件
- dup2(fd, 1); // 原子操作,功能等同于上面两句
- if(fd != 1){
- close(fd);
- }
- // 上面语句的功能相当于是将文件描述符1映射到打开的文件,即打开文件的文件描述符 fd = 1
- // puts默认打印到标准输出,但此时标准输出被关闭了
- // 文件描述符1其实指向的是打开的文件,因此puts打印到了打开的文件里
- puts("hello!");
- exit(0);
- }
- #include
- #include
- int fcntl(int fd, int cmd, ... /* arg */ );
-
- // fcntl() performs one of the operations described below on the open file descriptor fd.
- // The operation is determined by cmd.
-
- // fcntl() 根据提供的 cmd 来对输入的 fd 进行相关操作
- #include
- int ioctl(int fd, unsigned long request, ...);
-
- // ioctl 是设备驱动程序中设备控制接口函数
- // 一个字符设备驱动通常会实现设备打开、关闭、读、写等功能
- // 在一些需要细分的情境下,如果需要扩展新的功能,通常以增设 ioctl() 命令的方式实现。