#include <fcntl.h> int open(const char *path, int oflag, /* mode_t mode */ ); int openat(int fd, const char *path, int oflag, /* mode_t mode */ ); //返回文件描述符 STDIN_FILENO //标准输入 STDOUT_FILENO //标准输出 #include<fcntl.h> int creat(const char *path, mode_t moe); //返回文件描述符,负数表示错误 #include <unistd.h> int close(int fd); //关闭一个文件还会释放该进程在该文件上的所有锁记录 #include <unistd.h> off_t lseek(int fd, off_t offset, int whence); //1.若whence是 SEEK_SET,则将该文件的偏移量设置为距离文件开始出offset个 //字节 //2.若whence是 SEEK_CUR,则将该文件的偏移量设置为其当前值加offset, //offset可为正或负 //3.若whence是 SEEK_END,则将该文件的偏移量设置为文件长度加offset, //offset可正可负 #include <unistd.h> ssize_t read(int fd, void *buf, size_t nbytes); ssize_t write(int fd, const void *buf, size_t nbytes); //read成功,返回读到的字节数,如果已达到文件尾端则返回0 //读普通文件时,读要求的字节数之前已经达到文件尾端则返回0 /从终端设备读一次最多读一行 //从网络读,网络中的缓冲机制可能造成返回值小于所要求读的字节数 //当从管道或FIFO读时,若管道包含的字节少于所需的数量,那么read将返回实际 //可用的字节数 //当从某些面向记录的设备(如磁带)读时,一次最多返回一个记录 //当一信号造成中断,而已经读了部分数据时,在成功返回之前,该偏移量将增加 //实际读到的字节数 //write成功,返回实际写入的字节数 //原子性的执行读写操作 #include <unistd.h> ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset); ssize_t pwrite(int fd, void *buf, size_t nbytes, off_t offset); //复制文件描述符 #include <unistd.h> int dup(int fd); int dup2(int fd, int fd2); //同步刷新 #include <unistd.h> int fsync(int fd); int fdatasync(int fd); void sync(void); //sync只是将所有修改过的块缓冲区排入写队列,然后就返回,并不等待实际写 //磁盘操作结束 //一般系统守护进程30秒调用sync函数 //fsync函数只对文件描述符fd指定的一个文件起作用,并且等待写磁盘操作结束 //fdatasync函数类似fsync,但是只影响文件的数据部分,fsync还会同步更新 //文件的属性 //更改已经打开文件的属性 #include <fcntl.h> int fcntl(int fd, int cmd, /* int arg */); //fcntl函数有5种功能 //1.复制一个已经的描述符(cmd=F_DUPFD或F_DUPFD_CLOEXEC) //2.获取/设置文件描述符标志(cmd=F_GETFD或F_SETFD) //3.获取/设置文件状态标志(cmd=F_GETFL或F_SETFL) //4.获取/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN) //5.获取/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW) //杂物箱函数 #include <unistd.h> #include <sys/ioctl.h> //BSD and linux int ioctl(int fd, int request);
open函数的oflag参数
参数 | 含义 |
O_RDONLY | 只读打开 |
O_WRONLY | 只写打开 |
O_RDWR | 读,写打开 |
O_EXEC | 只执行打开 |
O_SEARCH | 只搜索打开 |
O_APPEND | 每次写时都追加到文件尾端 |
O_CLOEXEC |
把FD_CLOEXEC常量设置为文件描述符 |
O_CREAT |
若文件不存在则创建它,同时需要第三个参数指明 新文件的访问权限 |
O_DIRECTORY | 如果path不是目录则出错 |
O_EXCL |
如果同时指定了O_CREAT,而文件已存在则出错 次功能可测试一个文件是否存在若不存在则创建 |
O_NOCTTY |
如果path引用的是终端设备,则不将该设备分配作为 进程的控制终端 |
O_NOFOLLOW |
如果path引用的是一个符号链接则出错 |
O_NONBLOCK |
如果path引用的是一个FIFO,一个块特文件或一个字符特殊文件,则 此选项为文件的本次打开操作和后续的I/O操作设置为非阻塞方式 |
O_SYNC |
每次write等待物理I/O操作完成,包括由该write操作引起的文件属性更新 所需的I/O |
O_TRUNC |
如果此文件存在,而且为只写或读-写成功打开,则将其长度截断为0 |
O_TTY_INIT |
如果打开一个还未打开的终端设备,设置非标准termios参数值,使其符合Single UNIX Specificationi |
O_DSYNC |
每次write要等待物理I/O操作完成,但如果该写操作并不影响读取写入的数据, 则不需要等待文件属性被更新 |
O_RSYNC |
使每一个以文件描述符作为参数进行的read操作等待,直至所有对文件同一部分挂起 的写操作都完成 |
写空洞的例子
#include <fcntl.h> #include <stdio.h> #include <unistd.h> char buf1[] = "abcdefghij"; char buf2[] = "ABCDEFGHIJ"; int main(int argc, char *argv[]) { if(argc < 2) { printf("input create file path!\r\n"); return 1; } int fd; if( (fd=creat(argv[1],0755)) < 0 ) { printf("create error"); printf("\r\n"); } if( write(fd,buf1,10) != 10 ) { printf("buf write error"); printf("\r\n"); } if( lseek(fd,16384, SEEK_SET) == -1) { printf("lseek error"); printf("\r\n"); } if( write(fd,buf2,10) != 10 ) { printf("buf2 write error"); printf("\r\n"); } return 0; }
读写文件的例子,将一个文件读取,写入到另一个文件中
#include <fcntl.h> #include <stdio.h> #include <unistd.h> #define BUFFSIZE 4096 int main(int argc, char *argv[]) { if(argc < 3) { printf("input read path, write path\r\n"); return 1; } int r_fd; if( (r_fd=open(argv[1],O_RDONLY)) < 0 ) { printf("open error\r\n"); } int w_fd; if( (w_fd=creat(argv[2],0755)) < 0 ) { printf("create error\r\n"); } int num; char buf[BUFFSIZE]; while( (num=read(r_fd, buf, BUFFSIZE)) > 0) { if( write(w_fd, buf, num) != num ) { printf("write error\r\n"); } } if( num < 0 ) { printf("read error\r\n"); } return 0; }
读写文件时候,buf大小不同对影响的影响,12核/12G内存
buf大小 | 真正时间 | 用户时间 | 系统时间 |
512 | 3.269s | 0.077s | 2.523s |
1024 | 1.793s | 0.039s | 1.723s |
2048 | 1.682s | 0.015s | 1.214s |
4096 | 2.410s | 0.017s | 2.184s |
8192 | 5.404s | 0.009s | 1.218s |
16384 | 5.433s | 0.013s | 1.175s |
32768 | 5.396s | 0.005s | 1.188s |
65535 | 5.383s | 0.004s | 1.205s |
8M | 0.878s | 0.000s | 0.876s |
如果没每一次,调用fsync(fd)将内存刷新到磁盘上,性能结果如下:
buf大小 | 真实时间 | 用户时间 | 系统时间 |
1024 | 1m52.317s | 0.386s | 12.616s |
2048 | 1m7.329s | 0.086s | 8.528s |
4096 | 36.584s | 0.036s | 4.183s |
8192 | 20.883s | 0.085s | 2.886s |
16384 | 13.335s | 0.026s | 2.200s |
32768 | 9.761s | 0.020s | 1.711s |
65535 | 6.901s | 0.010s | 1.462s |
8M | 5.675s | 0.001s | 1.199s |
UNIX支持在不同进程共享打开文件,内核使用三种数据结构表示打开文件
1.每个进程再进程表中都有一个记录项,记录项中包含一张打开文件描述符表,可将其视为一个矢量,每个
描述符 占用一项,与每个文件描述符相关联的是:
a)文件描述符标志(close_on_exec)
b)指向一个文件表项的指针
2.内核为所有打开文件维持一张文件表,每个文件表项包含:
a)文件状态标志(读,写,添写,同步和非阻塞等)
b)当前文件偏移量
c)指向该文件v节点表项的指针
3.每个打开文件(或设备)都有一个v节点,linux没有v节点而是用通用的 i节点结构。v节点包含了文件类型和对
此文件进行各种操作的函数指针,对于大多数文件,v节点还包含了该文件的 i节点(i-node)。这些信息是在
打开文件时从磁盘上读入内存的,所以文件的所有相关信息都是随时可用的。
打开文件的内核数据结构
两个独立进程各自打开同一个文件
原子操作
早起的unix版本不支持O_APPEND选项,所以程序被编写成下列形式
if( lseek(fd,0L2) < 0 ) { err_sys("lseek error"); } if( write(fd, buf, 100) != 100 ) { err_sys("write error"); }
创建一个文件
if( (fd=open(path,O_WRONLY)) < 0 ) { if(errno == ENOENT) { if( (fd=creat(path,mode)) < 0 ) { err_sys("create error"); } } else { err_sys("open error"); } }
fcntl函数的cm参数有11个,先说明前8个,后3个跟锁有关
参数 | 含义 |
F_DUPFD | 复制文件描述符fd |
F_DUPFD_CLOEXEC |
复制文件描述符,设置与新描述符关联的FD_CLOEXEC文件描述符 标志的值,返回新文件描述符 |
F_GETFD |
对应于fd的文件描述符标志作为函数值的返回。当前只定义了一个文件 描述符标志FD_CLOEXEC |
F_SETFD | 对于fd设置文件描述符标志 |
F_GETFD | 对于fd设置文件描述符标志 |
F_GETFL | 对应于fd的文件状态标志作为函数值返回 |
F_SETFL |
将文件状态标志设置为第三个参数的值,可以更改的几个标志是 O_APPEND,O_NONBLOCK,O_SYNC,O_DSYNC,O_RSYNC, O_FSYNC和O_ASYNC |
F_GETOWN |
获取当前接收SIGIO和SIGURG信号的进程ID或进程组ID |
F_SETOWN |
设置接收SIGIO和SIGURG信息的进程ID或进程组ID |
对于F_GETFL的函数返回值,在open函数中有说明,返回下列内容
文件状态标志 | 说明 |
O_RDONLY | 只读打开 |
O_WRONLY | 只写打开 |
O_RDWR | 读写打开 |
O_EXEC | 只执行打开 |
O_SEARCH | 只搜索目录打开 |
O_APPEND | 追加写 |
O_NONBLOCK | 非阻塞模式 |
O_SYNC | 等待写完成(数据和属性) |
O_DSYNC | 等待写完成(仅数据) |
O_RSYNC | 同步读和写 |
O_FSYNC | 等待写完成(仅BSD和Mac) |
O_ASYNC | 异步I/O(仅BSD和Mac) |
/dev/fd
较新的系统都提供名为 /dev/fd 的目录,其目录项是名为 0,1,2,等的文件,打开文件/dev/fd/n 等效于复制
描述符n
cat命令对其采用了一种特殊处理
filter file2 | cat file1 - file3 | ipr //首先cat读file1,然后是标准输入,然后是file3 //如果cat支持/dev/fd 也可以改成 filter file2 | cat file1 /dev/fd/0 file3 | ipr
相关推荐
《UNIX环境高级编程》是一本深入探讨Linux/Unix系统编程的经典著作,对于任何希望在这些操作系统上进行系统级编程的开发者来说,都是不可或缺的参考书。这本书详细介绍了如何利用UNIX/Linux系统的API和工具来构建...
《UNIX环境高级编程》是一本深受程序员和...通过结合这两个文件,你可以获得更全面的学习资料,加深对UNIX环境高级编程的理解。无论是自学还是作为参考手册,这本书及其相关资料都能为你的UNIX编程之路提供强大的支持。
《UNIX环境高级编程》是一本深入探讨UNIX系统编程的权威参考书籍。它涵盖了UNIX编程的各个方面,从基础的UNIX系统结构和原理,到文件操作、进程控制、进程间通信、多线程编程、网络编程以及终端I/O和伪终端等内容。...
在UNIX环境中,文件I/O是程序与存储设备交互的基本方式,主要涉及五个核心函数:`open`、`read`、`write`、`lseek`和`close`。这些函数构成了不带缓存的I/O(unbuffered I/O),即每次读写操作都会直接调用内核的...
Unix I/O系统是操作系统的核心部分,它提供了对文件和设备进行输入输出操作的接口。本文主要总结了Unix下的I/O模型及其相关系统调用。 在Unix中,每个进程都有一个打开文件描述符表,用于存储指向文件inode的指针和...
### UNIX环境高级编程知识点概述 #### 一、UNIX基础知识 **1.1 引言** 在计算机科学领域,操作系统作为连接硬件与软件的桥梁,为应用程序提供了必要的服务,包括但不限于执行新程序、打开文件、读取文件内容、...
《UNIX环境高级编程》是一本深受程序员和系统管理员喜爱的经典之作,它由W. Richard Stevens撰写,对中国乃至全球的UNIX和Linux开发者具有深远影响。这本书深入浅出地讲解了在UNIX系统上进行程序开发的各种技术和...
书中除了介绍UNIX文件和目录、标准I/O库、系统数据文件和信息、进程环境、进程控制、进程关系、信号、线程、线程控制、守护进程、各种I/O、进程间通信、网络IPC、伪终端等方面的内容,还在此基础上介绍了众多应用...
《Unix环境高级编程》是一本深入探讨Unix操作系统编程的经典之作,由W. Richard Stevens撰写,是许多计算机科学专业学生和专业开发者的必备参考书。这本书详细介绍了如何在Unix系统上进行系统级编程,包括文件I/O、...
关于文件名称列表中的"UNIX环境高级编程",这可能表示所有章节的PDF文件都集中在一个同名的压缩包内。通常,这样的压缩文件会包含一系列按照章节命名的PDF,例如"第1章_进程管理.pdf"、"第2章_文件系统接口.pdf"等,...
《Unix环境高级编程》是一本深受程序员和系统管理员喜爱的经典之作,主要涵盖了在Unix操作系统环境下进行高级编程的各种技术和方法。这本书分为多个章节,详细讲解了Unix系统接口、进程管理、文件系统、网络通信等...
"UNIX环境高级编程"通常涵盖的主题包括进程管理、文件I/O、信号处理、网络编程、系统调用接口以及内存管理等。 课后习题往往旨在巩固和深化对这些概念的理解。以下是一些可能涉及的知识点: 1. **进程管理**:包括...
这本书涵盖了Unix系统的方方面面,包括进程管理、文件I/O、网络编程、信号处理、内存映射、多线程、进程间通信等核心主题。以下是一些主要知识点的详细介绍: 1. **进程管理**:Unix系统中的进程是程序执行的实例。...
unix环境高级编程 pdf高清无水印 第1章 UNIX基础知识 1 第2章 UNIX标准化及实现 17 第3章 文件I/O 35 第4章 文件和目录 54 第5章 标准I/O库 91 第6章 系统数据文件和信息 110 第7章 UNIX进程的环境 122 第8章 进程...
《UNIX环境高级编程第二版》是一本全面而深入的UNIX系统编程指南,它不仅教授了C语言在UNIX环境下的具体应用,还涵盖了文件I/O、进程控制、信号处理、网络编程等关键主题。通过阅读本书,读者将能够掌握UNIX系统编程...
《UNIX环境高级编程》是一本深受IT专业人士喜爱的经典著作,尤其对于那些致力于深入理解Linux操作系统以及UNIX系统的开发者和系统管理员而言,这本书具有极高的参考价值。作为“学习Linux最好的两本书之一”,它与...