文件相关系统调用接口:
以open函数调用为例,其打开后返回文件描述符
具体步骤如图:
PCB中fds(文件描述符)专门用来存储已打开的文件,它是一个数组类型
文件表中存储文件的打开标志、当前读写位置、引用计数、指向v节点的指针,v节点中存有指向i节点的指针
在linux下我们ls获取的信息就来自v节点表,i节点表中存放的是磁盘数据的存储位置
引用计数(refcnt):表示有几个文件描述符指向这个文件表,refcnt可能为2,因为子进程拷贝父进程内容时候,会拷贝父进程的文件描述符,此时父子进程的文件描述符指向同一个refcnt。当refcnt==0文件才释放,fclose是让refcnt-1。而一次open就拥有一个文件表,多次open并不影响refcnt
举个例子:
接口函数中有一个叫lseek
int lseek(int fd,off_t offset,int whence);
从指定位置开始读取,返回值为绝对偏移量,可以用来测文件的大小,其中fd为已打开的文件,offset为偏移量,whence为偏移量的基准位置
whence: SEEK_SET 表示文件的相对起始位置
SEEK_CUR 表示文件的相对当前位置
SEEK_END 表示文件的相对结束位置
返回值:新的相对于文件开头的字节数
这个函数的功能时如何实现的呢?它就是通过修改内核文件表中的读写位置达到从指定位置开始读写的。
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 #include<fcntl.h>
5 #include<string.h>
6 int main()
7 {
8 int fd=open("test.txt",O_RDONLY);
9 if(fd==-1)
10 {
11 perror("open");
12 exit(1);
13 }
14 while(1)
15 {
16 char buf;
17 int r=read(fd,&buf,1);
18 if(r<=0)
19 {
20 break;
21 }
22 else
23 {
24 write(1,&buf,1);
25 lseek(fd,1,SEEK_CUR);
26 }
27 }
28 close(fd);
29 }
~
补充一点:read、write时系统给的,fread、fwrite是c库函数里有的,系统中的I/O不带缓存,c库中的I/O带缓存
linux下七种文件类型:
其中套接字、块设备、字符设备、管道时伪文件,不占用磁盘空间
符号链接记录的是路径、路径不长时存在i节点里面
如何获取文件属性:
磁盘存储文件时除了存储文件内容还要存储与文件相关的信息。
我们可以通过ls读取存储在磁盘上的信息显示到用户空间,那么如何单独获取文件属性?
需要掉用stat函数:
引用头文件为:<sys/stat.h>
int stat(const char *path,struct stat *buf),指针不带const多半是传出型的参数,这里的buf就是传出型参数,返回的是文件相关信息。
举一个具体的使用例子:求文件大小(我们以st_size可以获取)
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 #include<sys/stat.h>
5 int main()
6 {
7 struct stat sbuf;
8 if(stat("./stattest.txt",&sbuf)==-1)
9 {
10 perror("stat");
11 exit(1);
12 }
13 else
14 {
15 printf("size:%d",sbuf.st_size);
16 }
17 }
我们编译执行一下,发现这里的size与我们ls-l获得的size一致: