由于在Linux系统中,文件几乎可以代表一切。因此,操作文件的函数也可以操作其他的一些设备/东西。
文件相关函数包括:文件读写函数/非读写函数
标C的文件读写函数:fopen() fread() fwrite() fclose()
标C取文件大小的函数:fseek(SEEK_END) 再调ftell()的返回值就是文件的大小
标C函数是不能直接访问内核,因此必须有文件相关的系统调用才能实现功能。文件读写系统函数:
open() read() write() close() ioctl()
其中ioctl()暂时不讲
open() 和close()
open()创建或是打开一个文件,返回文件描述符。
close()可以通过文件描述符关闭打开的文件。
文件描述符(在linux能打开256-3个,unix是64-3个):值为一个非负整数,用于表示一个打开文件。
文件描述符本身是一个非负整数,可以代表一个打开的文件。文件描述符的范围是3-openmax(打开的最大数量),Unix是64,Linux可以到255.0,1,2 被系统预先占用,代表标准输入/标准输出和标准错误。
文件描述符在关闭后可以重复使用。系统在选择文件描述符时,会找目前未使用的最小值。
文件描述符只是一个整数,如何代表一个打开的文件呢?
open()会打开一个文件,返回文件描述符
真实过程是:open()先找到硬盘上的文件,把文件的相关数据加载到内存中,放入文件表(可以看成结构体)中,找一个未使用的整数代表文件表,这个未使用的整数就是文件描述符。每个进程在启动时,都会创建一个文件描述符总表,存放文件描述符和文件表的对应关系。从表中找不到的整数就是未使用的。open()每返回一个描述符都会把这个描述符加入到总表中。而close()函数每关闭一个描述符,其实都是把描述符从总表中删除,不一定会删除文件表。一个文件表可以对应多个文件描述符,只有没有任何文件描述符与之对应的文件表才会被删除。
文件有两套数据,一套是文件在硬盘上的,一套是加载到内存中的。
文件在硬盘上是通过i节点进行管理的,i节点也是整数,i可以看成文件在硬盘上的地址,系统通过i节点(inode)找到文件和目录的。ls -i可以看i节点。
int open(char* filename,int flats,...)
功能:打开一个文件,并返回文件描述符
参数:filname就是文件名,要带路径
flags是文件打开的标识,由一些宏组成;
... 叫可变长参数,代表0-n任意类型的参数。
其中,flats的常见的值:
O_RDONLY O_WRONLY O_RDWR 三选一 打开文件的权限
O_CREAT 代表可以新建不存在的文件,需要第三个参数指定文件在硬盘上的权限
O_EXCL 代表如果文件存在,返回-1,而不是打开(只新建不打开)必须和O_CREAT结合使用
O_TRUC 代表如果文件存在,打开时清空文件的内容(小心使用,因为文件中的数据直接删除)
O_APPEND 代表以追加的方式代该文件,针对追加写
返回:成功返回文件描述符,失败返回-1.
int read(int fd,void* buf,int size)
int write(int fd,void* data,int length)
功能:读写文件函数
参数:fd都是文件描述符,buf是接收数据的首地址,size就是buf的大小,data是要写入的数据的首地址,length是数据的有效长度。
返回值:失败都返回-1,成功都返回 实际读取的字节数。
读文件时,返回0 代表读到了文件尾(结束条件)
目前为止,读写文件可以使用UC和标C函数。如何选择用uc还是标c呢?
time a.out 可以测试a.out的运行时间
标C的输入输出函数都有缓冲区的存在,因此真实的读写文件的次数和循环的系数是不一样的。而UC函数在用户层没有缓冲区。UC函数在频繁读写的时候需要程序员自定义缓冲区以提升效率。缓冲区的大小不是越大越好,可能需要测试,找到最佳大小。(标c函数也可以通过改变缓冲区的大小提升效率)