Linux的C语言文件操作
1.linux常用文件IO接口:open、close、write、read、lseek
2.操作文件现将文件从硬盘(在硬盘中称静态文件)加载到内存(在内存中称为动态文件),操作仅对于动态文件,关闭文件时同步到静态文件。
3.每操作产生一个动态文件,系统给新的动态文件分配一块内存和数据结构记录该动态文件,并给其分配一个文件描述符用来标识,作用域为该进程。即文件描述符的作用是区别同一进程中的不同文件。
4.文件打开,读写,关闭,函数
终端中,man 1 xxx 查shell,man 2 xxx 查API,man 3 xxx查库函数
int open(const char *pathname, int flags); ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void *buf, size_t count); int close(int fd);
例程
#include#include #include #include #include int main(int argc, char *argv[]) { int fd = -1; int readbyte = -1; int writebyte = -1; char readbuf[100]={0}; char writebuf[10] = "sfdsdsgfd"; fd = open("a.txt",O_RDWR); //open输入文件名,flag,返回文件描述符 if(fd == -1) { printf("文件打开失败\n"); } else { printf("文件打开成功,文件描述符为%d\n",fd); } readbyte = read(fd,readbuf,6); //read输入文件描述符,读取到的数组名,读取长度,返回读取长度 if(readbyte < 0) { printf("文件读取失败\n"); }else { printf("文件读取成功\n"); printf("%s\n",readbuf); } writebyte = write(fd,writebuf,5); //write输入文件描述符,放入的数组名,写入长度,返回写入长度 if(writebyte < 0) { printf("文件写入失败\n"); }else { printf("文件写入成功\n"); } close(fd); //close输入文件描述符 }
5.close的 flag
O_RDONLY O_WRONLY O_RDWR 分别为只读,只写,读写
当权限 | O_TRUNC, 新内容会替代原来的内容(原来的内容就不见了,丢了)
当权限 | O_APPEND, 新内容附加在后面,原来的内容还在前面
当权限 | O_CREAT 不管原来这个文件存在与否都能打开成功,如果原来这个文件不存在则创建一个空的新文件,如果原来这个文件存在则会重新创建这个文件,原来的内容会被消除掉(有点类似于先删除原来的文件再创建一个新的)
当权限 | O_CREAT | O_EXCL 没有文件时创建文件,有这个文件时会报错
O_CREAT作用:open函数在使用O_CREAT标志去创建文件时,可以使用第三个参数mode来指定要创建的文件的权限。mode使用4个数字来指定权限的,第一个0不用深究,其中后面三个很重要,对应我们要创建的这个文件的权限标志。譬如一般创建一个可读可写不可执行的文件就用0666(6就是rwx中rw是1,x是0)
O_NONBLOCK作用:我们打开一个文件默认就是阻塞式的(阻塞就是排队,非阻塞就是不排队),如果你希望以非阻塞的方式打开文件,则flag中要加O_NONBLOCK标志,只用于设备文件,而不用于普通文件。
O_SYNC 作用:write阻塞等待底层完成写入才返回到应用层,无O_SYNC时write只是将内容写入底层缓冲区即可返回,然后底层(操作系统中负责实现open、write这些操作的那些代码,也包含OS中读写硬盘等底层硬件的代码)在合适的时候会将buf中的内容一次性的同步到硬盘中。这种设计是为了提升硬件操作的性能和销量,提升硬件寿命;但是有时候我们希望硬件不好等待,直接将我们的内容写入硬盘中,这时候就可以用O_SYNC标志
O_APPEND作用:程序重复打开了同一个文件,O_APPEND将分别写改为接续写,分别写的内部原理就是2个fd拥有不同的文件指针,并且彼此只考虑自己的位移。但是O_APPEND标志可以让write和read函数内部多做一件事情,就是移动自己的文件指针的同时也去把别人的文件指针同时移动。(也就是说即使加了O_APPEND,fd1和fd2还是各自拥有一个独立的文件指针,但是这两个文件指针关联起来了,一个动了会通知另一个跟着动,O_APPEND对文件指针的影响,对文件的读写是原子的,原子操作的含义是:整个操作一旦开始是不会被打断的,必须直到操作结束其他代码才能得以调度运行,这就叫原子操作。每种操作系统中都有一些机制来实现原子操作,以保证那些需要原子操作的任务可以运行。
6.lseek:控制文件指针即光标的函数。
off_t lseek(int fd, off_t offset, int whence);
offset是相对于第三个输入的偏移量,第三个输入可以是 SEEK_SET SEEK_CUR SEEK_END,分别是文件头,当前位置,文件尾。
函数返回值是文件指针当前所在的位置
7.exit、_exit、_Exit退出进程
(1)当我们程序在前面步骤操作失败导致后面的操作都没有可能进行下去时,应该在前面的错误监测中结束整个程序,不应该继续让程序运行下去了。
(2)我们如何退出程序?
第一种;在main用return,一般原则是程序正常终止return 0,如果程序异常终止则return -1。
第一种:正式终止进程(程序)应该使用exit或者_exit或者_Exit之一。
8.文件IO效率和标准IO
(1)文件IO就指的是我们当前在讲的open、close、write、read等API函数构成的一套用来读写文件的体系,这套体系可以很好的完成文件读写,但是效率并不是最高的。
(2)应用层C语言库函数提供了一些用来做文件读写的函数列表,叫标准IO。标准IO由一系列的C库函数构成(fopen、fclose、fwrite、fread),这些标准IO函数其实是由文件IO封装而来的(fopen内部其实调用的还是open,fwrite内部还是通过write来完成文件写入的)。标准IO加了封装之后主要是为了在应用层添加一个缓冲机制,这样我们通过fwrite写入的内容不是直接进入内核中的buf,而是先进入应用层标准IO库自己维护的buf中,然后标准IO库自己根据操作系统单次write的最佳count来选择好的时机来完成write到内核中的buf(内核中的buf再根据硬盘的特性来选择好的实际去最终写入硬盘中)。
(3)标准IO是C库函数,而文件IO是linux系统的API
(4)库函数比API还有一个优势就是:API在不同的操作系统之间是不能通用的,但是C库函数在不同操作系统中几乎是一样的。所以C库函数具有可移植性而API不具有可移植性。
(5)性能上和易用性上看,C库函数一般要好一些。譬如IO,文件IO是不带缓存的,而标准IO是带缓存的,因此标准IO比文件IO性能要更高。
9.文件描述符:linux内核占用了0、1、2这三个fd是有用的,当我们运行一个程序得到一个进程时,内部就默认已经打开了3个文件,这三个文件对应的fd就是0、1、2。这三个文件分别叫stdin、stdout、stderr。也就是标准输入、标准输出、标准错误。标准输入一般对应的是键盘(可以理解为:0这个fd对应的是键盘的设备文件),标准输出一般是LCD显示器(可以理解为:1对应LCD的设备文件),printf函数其实就是默认输出到标准输出stdout上了。stdio中还有一个函数叫fpirntf,这个函数就可以指定输出到哪个文件描述符中。
10.fcntl函数是一个多功能文件管理的工具箱,接收2个参数+1个变参。第一个参数是fd表示要操作哪个文件,第二个参数是cmd表示要进行哪个命令操作。变参是用来传递参数的,要配合cmd来使用