浅谈Linux文件操作与文件描述符
一、简单的文件操作与函数介绍
1.open()
系统接口
#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);
这里提供了两个接口,根据实际情况选取合适的即可
通过man手册查看mode
mode指定在创建新文件时使用的权限。当在标志中指定O_CREAT时,必须提供此参数;
没有指定O_CREAT,则忽略模式。创建的文件的权限是(mode&~umask)。请注意,此模式仅适用于新创建的文件的未来访问。
函数参数:
pathname: 要打开或创建的目标文件
flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags
O_RDONLY: 只读打开 O_WRONLY: 只写打开 O_RDWR : 读,写打开前三个常量,必须指定一个且只能指定一个 O_CREAT : 若文件不存在,则创建它,需要使用mode选项,来指明新文件的访问权限 O_APPEND: 追加写 O_TRUNC:清空之前的内容
mode:描述打开文件的权限
函数返回值:
成功返回新的文件描述符,失败返回-1
注意:如果成功,open()返回文件描述符是用于后续系统调用的小的非负整数
2.write()
系统接口
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
函数参数
fd:要写入文件的文件描述符
buf:将该区域数据写入
size:写入数据的大小
函数返回值
成功返回读取数据大小,失败返回-1,0代表无写入
代码示例:
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h> //write
#include <string.h> //strlen
int main(){
int fd = open("./test.txt",O_CREAT | O_WRONLY,0644);
//读方式打开文件,如果没有则创建
if(fd < 0){
perror("open error");
return -1;
}
//打开成功
printf("打开文件按描述符为:%d\n",fd);
const char* str = "hello fd!\n";
write(fd,str,strlen(str));
close(fd);
return 0;
}
先开始没有文件
运行程序后生成test.txt文件,并且输出文件描述符
查看文件内容,hello fd!已经写入到文件中
3.read()
系统接口
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
函数参数
fd:从该文件描述符文件中读取数据
buf:把从fd读取的数据存放在此区域
count:读取数据的大小
函数返回值
成功返回读取数据的大小,失败返回-1,0表示读取到文件的结尾
注意:成功情况下的返回值不一定与count相等
代码示例:
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h> //read
#include <string.h> //strlen
#define LEN 1024
int main(){
int fd = open("./test.txt",O_RDONLY);
if(fd < 0){
perror("open error");
return -1;
}
char buffer[LEN];
ssize_t s = read(fd, buffer, sizeof(buffer)-1);
if(s > 0){
buffer[s] = 0;//手动设置字符串结尾
printf("%s\n", buffer);
}
close(fd);
return 0;
}
读取文件内容并输出
二、文件描述符
在上面我们了解了open,write,read的简单使用。但是,文件在磁盘中被打开的过程是什么呢?接下来就分析一下。
当用户从磁盘打开一个文件,这时候内存中就会形成一个struct file结构,然后从众多文件描述符当中,取最小未分配的文件描述符分配给文件,把struct file的地址存放在fd_array[最小未分配]当中。
示意图:
从前面的程序也可以看出,新建文件的fd都是从3开始的,什么原因呢?
其实在最开始,OS(操作系统)已经为我们打开了0,1,2号文件描述符,这三个分别是0->stdin, 1->stdout, 2->stderr,我们写个代码验证一下。
#include <stdio.h>
int main(){
printf("stdin -> %d\n", stdin->_fileno);
printf("stdout -> %d\n", stdout->_fileno);
printf("stderr -> %d\n", stderr->_fileno);
return 0;
}
运行结果如下:
在了解打开文件过程后,那么我们进行读写操作的时候会发生什么事情呢?
进程进行write,read操作的时候传入fd,这时候进程会在自己的PCB中找到files_struct,在其中找到fd_array[fd]中的内容,读取该内容也就找到了file 的位置,file结构体中有一个file_operations结构里面包含了文件的各种操作,此时就可以对根据需要对文件进行操作了。
示意图: