【Linux】零基础深入学习linux文件实用的系统(一)

c语言文件函数

写函数:

FILE* fp=fopen("myfile","w");
if(!fp)
{
perror("fopen");
}
const char* msg="hello jib\n";
int cnt=5;
while(cnt--)
{
fwrite(msg,strlen(msg),1,fp);
}
fclose(fp);

读函数:

fp=fopen("myfile","r");
char buf[1024];
size_t s=fread(buf,1,sizeof(buf)-1,fp);
fclose(fp);

详细的C语言文件知识点请看我这篇文章,这里不过多解释了
C语言文件操作知识

系统接口

读写函数:

umask(0);
int fd=open("myfile",O_RDWR|O_CREAT,0644);
if(fd<0)
{
perror("open");
return -1;
}
char* msg="hello world\n";
int cnt=5;
int len=strlen(msg);
while(cnt--)
{
write(fd,msg,len);
}
lseek(fd,0,SEEK_SET);
char buf[1024];
while(1)
{
size_t s=read(fd,buf,sizeof(buf)-1);
if(s>0)
{
buf[s]='\0';
printf("%s\n",buf);
}
else{
break;
}
}

在这里插入图片描述
lseek定位文件写入文件之后指针到了文件末尾

off_t lseek(int fd, off_t offset, int whence);

fd:文件描述符
offset:偏移量
whence:基准位置 分为:SEEK_SET SEEK_CUR SEEK_END

这里是定位文件开头

open

打开一个文件,

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

参数细节:
pathname 要创建或打开的文件名字

flags:打开文件时,可以传入多个参数选项,用下列一个或多个常量构成flags

  • O_RDONLY只读打开
  • O_WRONLY只写打开
  • O_RDWR可以读可以写

以上三种模式只能选一种

  • O_CREAT

若是要打开文件不存在,则创建这个文件

  • O_APPEND
    追加写,(下文重定向会讲)

返回值
成功了返回 文件描述符
失败了返回 -1

文件标识符

通过open,我们知道文件标识符就是一个整数

int fd=open("myfile",O_RDWR|O_CREAT,0644);
if(fd<0)
{
perror("open");
return -1;
}
cout<<fd<<endl;

在这里插入图片描述
系统分配文件标识符是从0开始的,为什么我新开的文件标识符是3呢?

因为系统自动打开了3个文件:
键盘,显示器,显示器 ,
分别是标准输入,标准输出,标准错误对应的文件标识符 0,1,2

所以输入输出还可以这样,

char buf[1024];
size_t s=read(0,buf,sizeof(buf)-1);
if(s>0)
{
buf[s]='\0';
write(1,buf,strlen(buf));
write(2,buf,strlen(buf));
}

在这里插入图片描述
在这里插入图片描述
PCB中有files指针,指向一张表files_struct,表中有file数组,数组中每个元素都是指向已打开文件的下标

所以文件标识符本质就是该数组的下标,只要有这个下标就能找到对应的文件

分配文件标识符

我们关闭0文件试试

close(0);
//close(2);
size_t fd=open("myfile",O_RDWR|O_CREAT);
if(fd<0)
{
perror("open");
}
else{
cout<<fd;
}

在这里插入图片
描述
结果系统把0文件标识符给了myfile
说明分配规则是从struct_file寻找到下标最小且未被使用的文件标识符

重定向

如果我们关闭1呢

close(1);
size_t fd=open("myfile",O_RDWR|O_CREAT);
if(fd<0)
{
perror("open");
return 1;
}
else{
cout<<fd;
}

在这里插入图片描述
运行发现无结果,为什么呢?
原本要向显示器打印的,但是显示器被关了,标识符1被myfile占了,但是系统依旧向1中输入,所以最终结果给了文件myfile

在这里插入图片描述
我们看到第一个hello的h被覆盖为1了,因为我之前向myfile中已经输入了许多hello world

要想清空文件,只需改变打开的方式

size_t fd=open(“myfile”,O_RDWR|O_CREAT|O_TRUNC);

在这里插入图片描述
或者追加模式
在这里插入图片描述
常见的重定向:>,>>,<
> 把内容输出到文件中
>>就是追加模式
< 把内容输入到指令中
比如cat < text.txt 但我们一般省略 <

小总

C语言的I/O函数其实是封装了系统函数,打开权限a就是封装了追加模式的系统函数,各种语言都有自己文件操作函数,但是本质都是封装了系统函数open,write等等

而且必定封装了fd,所有语言级别的文件操作函数都是通过fd完成的

缓冲区

先来看代码:

char* str="hello write\n";
char* fstr="hello fwrite\n";
cout<<"cout"<<endl;
fprintf(stdout,"hello fprintf\n");
fwrite(fstr,strlen(fstr),1,stdout);
write(1,str,strlen(str));

在这里插入图片描述
正常输出,如果加入fork()会怎样
在这里插入图片描述

正常运行还是没问题,问题来了,当我们向文件输入,我们发现,C语言的文件函数打印了两次,系统函数只打印了一次

为啥会这样呢??因为有缓冲区
C语言有自己的缓冲区

缓冲区刷新模式

  • 无缓冲 - - - 直接刷新
  • 行缓冲 - - - 不刷新,遇到\n刷新
  • 全缓冲 - - - 直到缓冲区满了才刷新

进程退出的时候也会刷新缓冲区

显示器刷新正常是行刷新,遇到\n就刷新,但当向文件中刷新时,显示器就变成了全缓冲即遇到\n不会立刻给你刷新,放入缓冲区里了

但是为什么C语言文件函数打印了两遍呢?
因为fork创建了子进程,子进程会复制当前的缓冲区,相当于C语言当前缓冲区有了两份,刷新了两遍缓冲区

为什么系统函数只打印了1遍呢 ?
因为操作系统内核有自己的缓冲区,也就是系统函数只在系统缓冲区一份

实际上,C语言的缓冲区要刷新到操作系统内核,然后再刷新系统缓冲区,目前我们认为,刷新到内核的数据就能到达硬件

解释下为什么cout只打印了一次,因为遇到关键词cout会立即刷新缓冲区
在这里插入图片描述

在这里插入图片描述
缓冲区存在FILE中,里面有打开文件的缓冲区字段和维护信息

所以之前讲的exit(),函数是刷新C语言缓冲区,在调用_exit()
_exit()直接退出,缓冲区也不刷新

posted on 2025-12-27 15:16  ljbguanli  阅读(41)  评论(0)    收藏  举报