• 【Linux】C文件系统详解(一)——C文件操作


    文件操作总结

    1.文件描述符,重定向,缓冲区,语言和系统关于文件的不同的视角的理解 – 都是要让我们深刻理解文件
    2.文件系统
    3.动静态库 – a.制作者的角度 b.站在使用者的角度 c.如何理解动态库加载(进程地址空间的内容)

    预备知识

    1.你真的理解文件原理和操作了吗?这不是语言问题,这是系统的问题
    2.是不是只有c/c++有文件操作呢?pytho java php go也有的,但是他们的文件操作的方法是不一样的,如何理解这种现象?有没有一种统一的视角看待所有的语言文件操作呢
    3.操作文件的时候,第一件事情,都是打开文件.打开文件是做什么呢,如何理解呢
    4.文件 = 内容 + 属性->针对文件的操作,对内容的操作,对属性的操作
    5.当文件没有被操作的时候,文件会在磁盘上
    6.当我们对文件进行操作时,文件会被放在内存上,因为冯诺依曼体系是这么规定的
    7.当我们对文件进行操作时,文件需要提前被load到内存,load的是内容还是属性呢?反正至少得有属性吧
    8.当我们对文件进行操作时,文件需要提前被load到内存,是不是只有你一个人在load呢?不是,内存中一定存在大量的不同文件的属性
    9.综上->打开文件本质就是将我们需要的文件属性加载到内存中,OS内部一定会同时存在大量的被打开的文件,那么OS要不要管理这些被打开的文件呢?先描述,再组织!构建在内存中的文件对象结构体,struct file{就可以从磁盘来,struct file* next} ,表明被打开的文件
    10.文件被打开,是谁在打开呢?OS,但是是谁让OS打开的呢? 用户(进程为代表的)
    11.我们之前的所有的文件操作,都是进程和被打开文件的关系
    12.进程和被打开文件的关系struct task_structstruct file的关系

    结论:

    1. 每一个被打开的文件,都要在OS内创建对应的struct结构体,可以将所有的struct file 结构体用某种数据结构链接起来,在OS内部,对被打开的文件进行管理,就被转换为了对链表的增删查改
      即:文件被打开,OS要为被打开的文件创建对应的内核结构
    struct file 
    {
    	//各种属性
    	//各种链接关系
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 文件其实可以被分成两大类:磁盘文件,被打开的文件(内存文件)

    C文件操作回顾

    语言方案

    w写入方式

    w: 默认写方式打开文件,如果文件不存在,就创建它
    1.默认如果只是打开,文件内容会自动清空
    2.同时,每次进行写入的时候,都会从最开始进行写入
    先清空,再写入

    #include
    #define LOG "log.txt"
    int main()
    {
    	
    	FILE* fp = fopen(LOG,"w");
    	if(fp == NULL)
    	{
    		return perror("fopen");
    		//fopen:xxxx
    		return 1;	
    	}
    	//正常进行文件操作
    	const char* msg = "hellp lx,hello 2023\n";
    	int cnt = 5;
    	while(cnt)
    	{
    		char buffer[256];
    		//int fprintf(FILE* stream,const char* format,...)
    		//指定文件流,向指定文件打印
    		fprintf(fp,"%s:%d:lx\n",msg,cnt)//往文件中输入
    		fprintf(stdout,"%s:%d:lx\n",msg,cnt)//linux一切皆文件,stdout对应显示器文件 
    		snprintf(buffer,sizeof(buffer),"%s:%d:lx\n"msg,cnt);//输入到自定义缓冲区中
    		fputs(buffer,fp);
    		
    		//fputs(msg,fp);
    		cnt--;
    	}
    
    	fclose(fp);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    a写入方式

    不会清空文件,而是每一次写入都是从文件结尾写入的,即追加

    #include
    #define LOG "log.txt"
    int main()
    {
    
    	FILE* fp = fopen(LOG,"a");
    	if(fp == NULL)
    	{
    		return perror("fopen");
    		//fopen:xxxx
    		return 1;	
    	}
    	//正常进行文件操作
    	const char* msg = "aaa\n";
    	int cnt = 5;
    	while(cnt)
    	{
    		fputs(msg,fp);
    		cnt--;
    	}
    
    	fclose(fp);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    r只读方式

    int main()
    {
    	FILE* fp = fopen(LOG,"r");
    	if(fp == NULL)
    	{
    		return perror("fopen");
    		//fopen:xxxx
    		return 1;	
    	}
    	//正常进行文件操作
    	while(1)
    	{
    		char line[128];
    		if(fgets(line,sizeof(line),fp) == NULL) break;
    		else 
    		{
    			printf("%s\n",line);
    		}
    	}
    
    	fclose(fp);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    系统方案

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #define LOG "log.txt"
    int main()
    {
    	//fd:文件描述符
    	int fd = open(LOG, O_WRONLY | O_CREAT);
    	if(fd == -1)
    	{
    		printf("fd:%d,errno:%d,errorstring:%s\n",fd,errno,strerror(errno));
    	}
    	else printf("fd:%d,errno:%d,errorstring:%s\n",fd,errno,strerror(errno));
    
    	close(fp);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    但是这个没有设置权限,需要这样改:

    //写和读
    
    //头文件不变
    int main()
    {
    	//fopen(LOG,"w");
    	umask(0);//文件权限受掩码的影响
    	//fd:文件描述符
    	//O_CREAT和O_WRONLY不对原始内容清空
    	int fd = open(LOG, O_WRONLY | O_CREAT| O_TRUC, 0666);
    	if(fd == -1)
    	{
    		printf("fd:%d,errno:%d,errorstring:%s\n",fd,errno,strerror(errno));
    	}
    	else printf("fd:%d,errno:%d,errorstring:%s\n",fd,errno,strerror(errno));
    	//C语言,和这个接口的关系是什么呢?
    	//C标准库函数底层是调用系统调用
    
    	const char *msg = "hello lx,hollo world";
    	
    	int cnt = 5;
    	while(cnt)
    	{
    		char line[128];
    		snprintf(line,sizeof(line),"%s,%d\n",msg,cnt);
    		write(fd,line,strlen(line));
    		//这里的strlen不应该加1,因为\0结尾是C语言的规定,不是文件的规定!
    	}
    	close(fp);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    //追加(且)写入
    
    int fd = open(LOG, O_WRONLY | O_APPEND | O_CREAT, 0666);
    	if(fd == -1)
    	{
    		printf("fd:%d,errno:%d,errorstring:%s\n",fd,errno,strerror(errno));
    	}
    	else printf("fd:%d,errno:%d,errorstring:%s\n",fd,errno,strerror(errno));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    //读取文件(r)
    
    int fd = open(LOG, O_RDONLY);
    	if(fd == -1)
    	{
    		printf("fd:%d,errno:%d,errorstring:%s\n",fd,errno,strerror(errno));
    	}
    	else printf("fd:%d,errno:%d,errorstring:%s\n",fd,errno,strerror(errno));
    
    	char buffer[1024];
    	// 这里我们无法做到按行读取,我们是整体读取的
    	size_t n = read(fd,buffer,sizeof(buffer - 1));//使用系统接口进行IO时,一定要注意\0问题
    	if(n > 0)
    	{
    		buffer[n] = '\0';
    		printf("%s\n",buffer);
    	}
    	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    ![[Pasted image 20230318122921.png]]

    未完待续…

  • 相关阅读:
    cmip6数据如何下载?您是利用官方网站手动人工下载还是半自动购物车方式?
    ajax实现文件的下载
    Eclipse跌落神坛,逐渐被Visual Studio Code等新兴IDE占据市场
    找搭子平台小程序开发制作方案
    基于springboot的社区团购系统设计与实现
    opensearch与elasticsearch对比
    R语言缺失时间序列的填充及合并:补齐时间序列数据中所有缺失的时间索引、使用merge函数合并日期补齐之后的时间序列数据和另外一个时间序列数据(补齐左侧数据)
    Java的环境配置
    输出司机和乘客重合的时间点
    【Proteus仿真】【Arduino单片机】继电器和按键
  • 原文地址:https://blog.csdn.net/weixin_62712120/article/details/134466704