IO day3
- 文件IO
- 文件描述符
- 分配过程
- 相关函数
- 作业
文件IO
- 文件IO:基于系统调用的API函数接口
- 特点:每一次调用文件IO,系统都会从用户态到内核态之间切换,效率很低
- 作用:后期学习进程间通信,管道,SOCKET套接字通信,都会用到文件IO
文件描述符
- 本质上是一个非负整数,类似于标准IO打开文件时的 fp指针
- 进程执行时默认打开3个文件描述符0(
stdin
),1(stdout
),2(stderr
) - 文件描述符可以使用
ulimit -a
查看打开文件个数。使用 ll 查看文件权限 - 分配原则,按照最小未分配原则,而且每一个终端进程打开文件的个数是有限制的最多是1024个文件
分配过程
标准文件描述符:
- 文件描述符 0:标准输入(
stdin
) - 文件描述符 1:标准输出(
stdout
) - 文件描述符 2:标准错误(
stderr
) - 当您打开一个新文件时,操作系统会查找当前进程中未使用的最小文件描述符,并将其分配给新打开的文件。
- 如果所有文件描述符都已被使用,您将无法打开更多文件,直到关闭某些文件或进程结束。
- 关闭文件:使用 close函数关闭文件时,操作系统会释放该文件描述符,使其可以被后续的文件打开操作重新使用
相关函数
- open和close
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>int open(const char *pathname, int flags);int open(const char *pathname, int flags, mode_t mode);功能:打开或者创建文件。参数1:文件的路径和文件名参数2:打开或者创建文件时的语义O_CREAT:创建文件O_RDONLY:只读模式O_WRONLY :只写模式O_RDWR:读写模式O_EXCL:如果文件存在就报错O_TRUNC:清空文件内容。O_APPEND:追加写的方式以上选项可以按照位或方式组合使用。参数3:可选项如果参数2有O_CREAT或者O_TMPFILE,参数3必须加上创建时的权限,如果没有参数3直接省略。参数3是文件或者文件夹创建时的权限。返回值:成功返回文件描述符,失败返回-1,并置位错误码。文件夹的默认最大权限是775,文件的默认最大权限是664。eg:w:open("./1.txt",O_CREAT|O_TRUNC|O_WRONLY,0664);r:open("./1.txt",O_RDONLY);r+:open("./1.txt",O_RDWR);w+:open("./1.txt",O_CREAT|O_TRUNC|O_RDWR,0664);a:open("./1.txt",O_CREAT|O_APPEND|O_WRONLY,0664);a+:open("./1.txt",O_CREAT|O_APPEND|O_RDWR,0664);还可以有以下使用规则:open("./1.txt",O_CREAT|O_EXCL|O_RDWR,0664);//只创建读写文件,如果文件存在就报错。open("./1.txt",O_CREAT|O_EXCL|O_TRUNC|O_WRONLY,0664);//只写创建,清空打开文件,如果文件存在就报错 int close(int fd);功能:关闭open函数打开的文件描述符。参数:文件描述符(文件句柄)返回值:成功返回0,失败返回-1,并置位错误码。
- write和read
#include <unistd.h>ssize_t write(int fd, const void *buf, size_t count);功能:向fd指向的描述符写入内容,写count个字节参数1:文件描述符参数2:写入的内容参数3:写入的字节数。返回值:成功返回写入的字节个数,如果什么都没写入返回0,失败返回-1,并置位错误码。ssize_t read(int fd, void *buf, size_t count);功能:从fd指向的文件读取count个字节到buf中参数1:文件描述符 参数2:读取的内容参数3:读取的字节数。返回值:成功返回读取的字节数,读取到文件末尾返回0,失败返回-1,并置位错误码。
- lseek
#include <sys/types.h>#include <unistd.h>off_t lseek(int fd, off_t offset, int whence);功能:移动文件光标参数1:文件描述符参数2:偏移量>0:往后偏移<0:往前偏移=0:不偏移参数3:偏移的起始位置SEEK_SET:从文件的开头开始偏移SEEK_CUR:从当前位置开始偏移SEEK_END:从文件末尾开始偏移返回值:成功返回文件开头到光标之间的字节数,失败返回-1并置位错误码。eg:将光标偏移到文件末尾int len = lseek(fd,0,SEEK_END); len是文件的总大小。
- dup和dup2
- dup和dup2在赋值(复制)新描述符时新旧描述符都共享光标
- dup会产生新的描述符遵循最小未分配原则
- dup2不会产生新的描述符,只会先将新描述符指向的文件关闭,然后重定向新描述符到旧描述符文件
#include <unistd.h>int dup(int oldfd);功能:将文件描述符拷贝一份生成新的描述符,新旧木薯淀粉指向同一个文件,并且共享文件光标。参数:旧的描述符。返回值:成功返回创建的新描述符,失败返回-1,并置位错误码。int dup2(int oldfd, int newfd);功能:将新的描述符重定向给旧的描述符,新的描述符指向的文件会被关闭,然后新旧描述符都指向旧的文件,并且共享文件光标。注意:dup2不会像dup那样产生新描述符并且也不会遵循最小未分配原则。返回值:成功返回原本新描述符,但是新描述符值没有变化(重定向到旧的描述符),失败返回-1并置位错误码。
作业
使用read和write实现拷贝文件,将1.txt内容的前一半和后一半分别拷贝给2.txt和3.txt
#include <myhead.h>int main(int argc, const char *argv[])
{int fd1 = open("./1.txt", O_RDONLY); //只读方式打开1.txtif (-1 == fd1){perror("open");return -1;}int fd2 = open("./2.txt", O_WRONLY | O_CREAT | O_TRUNC); //只写方式打开2.txtif (-1 == fd2){perror("open");return -1;}int fd3 = open("./3.txt", O_WRONLY | O_CREAT | O_TRUNC); //只写方式打开3.txtif (-1 == fd3){perror("open");return -1;}int len = lseek(fd1,0,SEEK_END); //计算1.txt的长度lseek(fd1,0,SEEK_SET); //光标重置char *buff = (char *)malloc(len/2+1); //定义数组用于存储数据int res = read(fd1,buff,len/2); //从fd1中读取前一半数据write(fd2,buff,res); //写入fd2中bzero(buff,len/2+1); //清空数组res = read(fd1,buff,len/2); //从fd1中读取后半段数据write(fd3,buff,res); //写入fd3中 close(fd1);close(fd2);close(fd3);return 0;
}
运行结果