- 文件描述符:是一个非负数-操作文件的句柄,其实就是内核中一个进程打开的文件描述信息表的下标,通过这个下标可以在内核中找到相应的文件描述信息,通过这个描述信息实现文件操作
打开一个文件如果不操作了一定要关闭释放资源;文件描述符是有限的;若不关闭文件,文件描述符用光,则在进程中就打不开新文件了
由上图可以看到文件描述符是从3开始的,为什么呢?
一个程序运行起来,进程会默认打开三个文件:标准输入-0 / 标准输出-1 / 标准错误-2
文件描述符分配规则:最小未使用
代码说明:
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
int main()
{
close(0);//关闭0号描述符
umask(0);
int fd=open("./test.txt",O_RDWR|O_CREAT,0664);
if(fd<0){
perror("open error");
return -1;
}
printf("%d\n",fd);
close(fd);
}
close(0);关闭了标准输入,根据文件描述符分配规则,此时test.txt的文件描述符就变成了0
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
int main()
{
close(1);//关闭1号描述符
umask(0);
int fd=open("./test.txt",O_RDWR|O_CREAT,0664);
if(fd<0){
perror("open error");
return -1;
}
printf("%d\n",fd);
fflush(stdout);//刷新标准输出缓冲区
close(fd);
}
啥也没的
打开test.txt有打印内容
close(1);关闭标准输出,printf函数是打印数据到标准输出,而此时标准输出关闭了,打开新文件后,printf并没有把数据打印出来,而是刷新缓冲区后,将数据写入到了文件中。这就是重定向的原理,即将数据不再写入原本文件,而是写入新的指定的文件中,实现方式就是替换这个描述符对应的文件描述信息;实际上是描述符的重定向,改变描述符所指向的文件,就改变了数据的流向
- int dup2(int oldfd,int newfd);//描述符重定向
让newfd这个描述符也指向oldfd所指向的文件,这时候oldfd和newfd都能操作oldfd所指向的文件
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
int main()
{
//close(1);//关闭1号描述符
umask(0);
int fd=open("./test.txt",O_RDWR|O_CREAT,0664);
if(fd<0){
perror("open error");
return -1;
}
dup2(fd,1);//将1重定向到test.txt这个文件
printf("fd=%d\n",fd);
fflush(stdout);//刷新标准输出缓冲区
close(fd);
}
啥也没的
打开test.txt文件有打印内容
系统IO调用接口
- int open( char *filename , int flag , mode_t mode);
1)相关解读
- 参数:(要打开的文件名称,选项,权限)
- flag :选项参数 打开方式
必选项(只能选择其一):
O_RDONLY :只读
O_WRONLY :只写
O_RDWR :读写
可选项:
O_CREAT :文件存在则打开,不存在则创建
O_EXCL与O_CREAT同时使用(O_CREAT|O_EXCL):文件存在则报错,不存在则创建
O_TRUNC:打开文件的同时清空原有内容
O_APPEND:追加写,总是将数据写入到文件末尾- mode :权限,八进制数字形式
注意:如果使用了O_CREAT有可能创建新文件,一定要指定文件权限- 返回值:一个非负整数-文件描述符-文件的操作句柄;失败返回-1
2)代码测试:
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<unistd.h>
int main()
{
int fd=-1;
fd=open("./test.txt",O_RDWR);
if(fd<0){
perror("open error");
return -1;
}
close(fd);
return 0;
}
- [ test.txt文件删除后运行会打开失败]
int main()
{
int fd=-1;
fd=open("./test.txt",O_RDWR|O_CREAT);//二进制操作
if(fd<0){
perror("open error");
return -1;
}
close(fd);
return 0;
}
- [ 此时test.txt没有设置权限,权限是随机值]
int main()
{
int fd=-1;
umask(0);//将当前进程的文件创建权限掩码设置为0,这样的话,我们底下的权>限设置为多少就是多少,否则,最终文件权限=设置权限&~umask(0002);仅当前进程有效
fd=open("./test.txt",O_RDWR|O_CREAT,0777);//二进制操作
if(fd<0){
perror("open error");
return -1;
}
close(fd);
return 0;
}
- [ 设置完权限之后]
int main()
{
int fd=-1;
umask(0);//将当前进程的文件创建权限掩码设置为0,这样的话,我们底下的权>限设置为多少就是多少,否则,最终文件权限=设置权限&~umask(0002)
fd = open("./test.txt",O_RDWR|O_CREAT|O_EXCL,0777);//二进制操作
if(fd<0){
perror("open error");
return -1;
}
close(fd);
return 0;
}
- [ 验证O_CREAT|O_EXCL,此时test.txt存在,所以会报错]
- ssize_t write(int fd , char *buf , size_t count);
1)相关解读
- ssize_t:有符号32位整数
- 参数
fd:open返回的文件描述符-文件操作句柄,,通过fd指定要往哪个文件写入数据
buf:要写入文件的数据的空间首地址
count:要写入的数据大小- 返回值:返回实际写入文件的数据字节长度,错误返回-1
2)代码测试
int main()
{
int fd=-1;
umask(0);//将当前进程的文件创建权限掩码设置为0,这样的话,我
们底下的权限设置为多少就是多少,否则,最终文件权限=设置权限&~umask(0002)
fd = open("./test.txt",O_RDWR|O_CREAT,0777);//二进制操作
if(fd<0){
perror("open error");
return -1;
}
char *ptr="You are so cute!\n";
int ret=write(fd,ptr,strlen(ptr));
if(ret<0){
perror("write error");
return -1;
}
printf("ret:%d\n",ret);
close(fd);
return 0;
}
- ssize_t read(int fd , char *buf , size_t count);
- 参数
fd:open返回的文件描述符-文件操作句柄,,通过fd指定要往哪个文件写入数据
buf:从文件中读取数据放到哪块缓冲区的首地址
count:想要读取的数据长度,注意这个count不能大于缓冲区的大小- 返回值:返回实际读取到的数据字节长度;错误返回-1
- off_t lseek( int fd , off_t offset , int whence );
- 参数
off_t理解为int就行
fd :open返回的文件描述符
offset:偏移量
whence:从哪里开始偏移
SEEK_SET:文件起始位置;SEEK_CUR:文件当前读写位置;SEEK_END:文件末尾- 返回值:成功返回当前位置相对于起始位置的偏移量;失败返回-1
- int close( int fd );
通过文件描述符关闭文件,释放资源
代码测试:
int main()
{
int fd=-1;
umask(0);//将当前进程的文件创建权限掩码设置为0,这样的话,我
们底下的权限设置为多少就是多少,否则,最终文件权限=设置权限&~umask(0002)
fd = open("./test.txt",O_RDWR|O_CREAT,0777);//二进制操作
if(fd<0){
perror("open error");
return -1;
}
lseek(fd,0,SEEK_END);//目的读写位置跳转到文件末尾
char ptr[1024] ="You are so cute!\n";
int ret=write(fd,ptr,strlen(ptr));
if(ret<0){
perror("write error");
return -1;
}
printf("ret:%d\n",ret);
lseek(fd,0,SEEK_SET);//跳转到文件起始位置开始读取
char buf[1024]={0};
ret=read(fd,buf,1024);
if(ret<0){
perror("read error");
return -1;
}
printf("ret:%d-[%s]\n",ret,buf);
close(fd);
return 0;
}