• 文件操作【c语言】


    使用的函数文件下载地址

    不错的分享(推荐C++复杂版)
    C语言库函数查询手册(C参考手册大全)

    1 为什么使用文件

    • 程序中的数据无法做到持久化
    • 解决:使用文件操作实现数据持久化

    2 文件种类

    在程序设计中,从文件功能的角度分为:程序文件,数据文件

    • 文件分为两种
      • 程序文件
        • 包括源程序文件(后缀为.c),目标文件(windows环境后缀为.0bj)可执行程序(windows环境后缀为.exe)
      • 数据文件
        • 文件的内容不一定是程序而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件

    2.1 文件名

    • 一个文件需要一个唯一标识,以便用户识别和使用
    • 文件名包含3部分:文件路径+文件名主干+文件后缀
    • 例如:C:\code\test.bat
    • 0为了方便起见,文件标识常被称为文件名

    3 文件的打开和关闭

    3.1 文件指针

    • 缓冲文件系统中,关键的概念是***“文件类型指针”,简称“文件指针”***
    • 每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的该结构体类型是有系统声明的,
      取名FILE。
    • 不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异
    • 每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息使用者不必关心细节
    • 一般都是通过一个FLLE的指针来维护这个FILE结构的变量,这样使用起来更加方便
    FILE*pf://文件指针变量
    
    • 1
    • 定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。
    • 理解图如下
      在这里插入图片描述

    3.2 文件的打开和关闭

    • 文件在读写之前应该先打开文件,在使用结束之后应该关闭文件
      在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了,指针和文件的关系。
    • ANSIC规定使用fopen函数来打开文件,fclose来关闭文件。
    //打开文件
    FILE* fopen(Const char* filename ,const char* mode);
    //关闭文件
    int fclose(FILE* stream);
    
    • 1
    • 2
    • 3
    • 4
    • 模板
    #include
    int mian() {
    	FILE* pf=fopen("test.dat","w");
    	if(pf==null) {
    		perror("fopen");
    		renturn 1;
    	}
    	//写文件相关操作
    	
    	//关闭文件
    	fclose(pf);
    	pf=NULL;
    	renturn 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    文件使用方式含义如果指定文件不存在
    “r”(只读)为了输入数据,打开一个已经存在的文本文件出错
    “w”(只写)为了输出数据,打开一个文本文件建立一个新的文件
    “a”(追加)向文本文件尾添加数据建立一个新的文件
    “rb”(只读)为了输入数据,打开一个二进制文件出错
    “wb”(只写)为了输出数据,打开一个二进制文件建立一个新的文件
    “ab”(追加)向一个二进制文件尾添加数据出错
    “r+”(读写)为了读和写,打开一个文本文件出错
    “w+”(读写)为了读和写,建立一个新的文件建立一个新的文件
    “a+”(读写)打开一个文件,在文件尾进行读写建立一个新的文件
    “rb+”(读写)为了读和写打开一个二进制文件出错
    “wb+”(读写)为了读和写,新建一个新的二进制文件建立一个新的文件
    “ab+”(读写)打开一个二进制文件,在文件尾进行读和建立一个新的文件
    功能函数名适用于
    字符输入函数fgetc所有输入流
    字符输出函数fputs所有输出流
    文本行输入函数fgets所有输入流
    文本行输出函数fputs所有输出流
    格式化输入函数fscanf所有输入流
    格式化输出函数fprintf所有输出流
    二进制输入fread文件
    二进制输出fwrite文件

    4 文件的顺序读写

    fgetc

    在这里插入图片描述
    在这里插入图片描述

    #define _CRT_SECURE_NO_WARNINGS
    #include
    #include
    #include
    int main() {
    	FILE* pf = fopen("test.dat", "r");
    	if (pf == NULL) {
    		perror("fopen");
    		return 1;
    	}
    	//读文件
    	int ret = fgetc(pf);
    	printf("%c\n",ret);
    	ret = fgetc(pf);
    	printf("%c\n", ret);
    	ret = fgetc(pf);
    	printf("%c\n", ret);
    	//关闭文件
    	fclose(pf);
    	pf = NULL;
    
    	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

    fputs

    在这里插入图片描述
    在这里插入图片描述

    int main() {
    	char arr[10] = { 0 };
    	FILE* pf = fopen("test.dat", "w");
    	if (pf == NULL) {
    		perror("fopen");
    		return 1;
    	}
    	//写文件
    	fputs("abcdef\n",pf);
    	fputs("hdfakgndflkng\n",pf);
    	//关闭文件
    	fclose(pf);
    	pf = NULL;
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    fgets

    在这里插入图片描述
    在这里插入图片描述

    int main() {
    	char arr[10] = { 0 };
    	FILE* pf = fopen("test.dat", "r");
    	if (pf == NULL) {
    		perror("fopen");
    		return 1;
    	}
    	
    	//读文件
    	fgets(arr,4,pf);
    	printf("%s\n",arr);
    	fgets(arr, 4, pf);
    	printf("%s\n", arr);
    	//关闭文件
    	fclose(pf);
    	pf = NULL;
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    fwrite

    在这里插入图片描述
    在这里插入图片描述

    struct S
    {
    	char arr[10];
    	int age;
    	float sc;
    };
    int main() {
    	struct S s = { "hi",24,34.5f};
    	FILE* pf = fopen("test.dat", "w");
    	if (pf == NULL) {
    		perror("fopen");
    		return 1;
    	}
    
    	//写文件
    	fwrite(&s,sizeof(struct S), 1, pf);
    	printf("%s %d %f\n",s.arr,s.age,s.sc);
    	//关闭文件
    	fclose(pf);
    	pf = NULL;
    
    	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

    在这里插入图片描述

    struct S
    {
    	char arr[10];
    	int age;
    	float sc;
    };
    int main() {
    	struct S s = { 0};
    
    	FILE* pf = fopen("test.dat", "r");
    	if (pf == NULL) {
    		perror("fopen");
    		return 1;
    	}
    
    	//写文件
    	fread(&s,sizeof(struct S), 1, pf);
    	printf("%s %d %f\n",s.arr,s.age,s.sc);
    	//关闭文件
    	fclose(pf);
    	pf = NULL;
    
    	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

    在这里插入图片描述

    sprintf

    在这里插入图片描述

    int main() {
    	struct S s = {"hi",23,45.7f};
    	char buf[100] = {0};
    	//sprintf 把一个格式化的数据,转化成字符串
    	sprintf(buf,"%s %d %f\n",s.arr,s.age,s.sc);
    	printf("%s\n",buf);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    sscanf

    struct S
    {
    	char arr[10];
    	int age;
    	float sc;
    };
    int main() {
    	struct S s = {"hi",23,45.7f};
    	struct S tmp = {0};
    	char buf[100] = {0};
    	//sprintf 把一个格式化的数据,转化成字符串
    	sprintf(buf,"%s %d %f\n",s.arr,s.age,s.sc);
    	printf("%s\n",buf);
    	//从buf字符串中还原出一个结构体数据
    	sscanf(buf,"%s %d %f",&(tmp.arr),&(tmp.age),(&tmp.sc));
    	printf("%s %d %f\n",tmp.arr,tmp.age,tmp.sc);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    4.1 函数对比

    函数详解
    scanf针对标准输入的格式化的输入语句-stdin
    fscanf针对所有输入流的格式化的输入语句-stdin/文件
    sscanf从一个字符串中读取一个格式化的数据
    printf针对标准输出的格式化输出语句
    fprintf针对所有输出流的格式化输出语句-stdout/文件
    sprintf把一个格式化的数据,转换成字符

    5 文件的随机读写

    fseek

    根据文件指针的位置和偏移量来定位文件指针

      int fseek( FILE *stream, long int offset, int origin );
    
    • 1

    在这里插入图片描述

    int main() {
    	
    	FILE* pf = fopen("test.txt", "r");
    	if (pf == NULL) {
    		perror("fopen");
    		return 1;
    	}
    	//读取文件
    	int ch = fgetc(pf);
    	printf("%c \n",ch);//a
    	//调整文件指针
    	fseek(pf,2,SEEK_CUR);
    	ch = fgetc(pf);
    	printf("%c\n",ch);//d
    	ch = fgetc(pf);
    	printf("%c\n", ch);//e
    	//关闭文件
    	fclose(pf);
    	pf = NULL;
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    ftell

    返回文件指针相对于起始位置的偏移量

    long int(FILE* stream);
    
    • 1

    在这里插入图片描述

    int main() {
    	
    	FILE* pf = fopen("test.txt", "r");
    	if (pf == NULL) {
    		perror("fopen");
    		return 1;
    	}
    	//读取文件
    	int ch = fgetc(pf);
    	printf("%c \n",ch);//a
    	//调整文件指针
    	fseek(pf,2,SEEK_CUR);
    	ch = fgetc(pf);
    	printf("%c\n",ch);//d
    	ch = fgetc(pf);
    	printf("%c\n", ch);//e
    
    	int ret = ftell(pf);
    	printf("%d\n",ret);
    	//关闭文件
    	fclose(pf);
    	pf = NULL;
    
    	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

    frewind

    在这里插入图片描述

    int main() {
    	
    	FILE* pf = fopen("test.txt", "r");
    	if (pf == NULL) {
    		perror("fopen");
    		return 1;
    	}
    	//读取文件
    	int ch = fgetc(pf);
    	printf("%c \n",ch);//a
    	//调整文件指针
    	fseek(pf,2,SEEK_CUR);
    	ch = fgetc(pf);
    	printf("%c\n",ch);//d
    	ch = fgetc(pf);
    	printf("%c\n", ch);//e
    	//返回文件指针相对于起始位置的偏移量
    	int ret = ftell(pf);
    	printf("%d\n",ret);
    	//让文件指针回到起始位置 
    	rewind(pf);
    	ch=fgetc(pf);
    	printf("%c\n",ch);//a
    	//关闭文件
    	fclose(pf);
    	pf = NULL;
    
    	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

    6 文本文件和二进制文件

    文件分类

    • 根据数据的组织形式,数据文件被称为文本文件或者二进制文件
    • 数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件
    • 如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件
    • 一个数据在内存中的存储?
    • 字符一律以ASCI形式存储,数值型数据既可以用ASC形式存储,也可以使用二进制形式存储
      • 如有整数10000,如果以ASCI码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节(VS2013测试)
        在这里插入图片描述

    7 文件读取结束的判定

    在这里插入图片描述

    7.1 被错误使用的feof

    • 牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。
    • 而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到支件属结束。
    1. 文本文件读取是否结束,判断返回值是否为EOF(fgetc)或者NULL(fgets)
      • 例如:
        • ofgetc判断是否为EOF
        • fgets判断返回值是否为NULI
    2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数
      • 例如:
        • ofread判断返回值是否小于实际要读的个数

    fgetq函数在读取结束的时候,会返回EOF
    正常读取的时候,返回的是读取到的字符的ASCII码值
    fgets函数在读取结束的时候,会返回NULL
    正常读取的时候,返回存放字符串的空间起始地址
    fread函数在读取的时候,返回的是实际读取到的完整元素的个数
    如果发现读取到的完整的元素的个数小于指定的元素个数,这就是最后一次读取

    int main() {
    
    	FILE* pfread = fopen("test.txt", "r");
    	if (pfread == NULL) {
    		perror("fopen");
    		return 1;
    	}
    	FILE* pfwrite = fopen("test2.txt", "w");
    	if (pfwrite == NULL) {
    		fclose(pfread);
    		pfread = NULL;
    		return 1;
    	}
    	//文件打开成功
    	//读写文件
    	int ch = 0;
    	while ((ch = fgetc(pfread)) != NULL)
    	{
    		//写文件
    		fputc(ch,pfwrite);
    	}
    	if (feof(pfread)) {
    		printf("遇到文件结束标志,文件正常结束!\n");
    	}
    	else if (ferror(pfread)) {
    		printf("文件读取失败!\n");
    	}
    	//关闭文件
    	fclose(pfread);
    	pfread = NULL;
    	fclose(pfwrite);
    	pfwrite = NULL;
    
    	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
    • 33
    • 34
    • 35

    在这里插入图片描述

    8 文件缓冲区

    • 标准采用“缓冲文件系统”处理的数据文件的,ANSIC所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区)),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。
      在这里插入图片描述
  • 相关阅读:
    Springboot整合WebSocket实现浏览器和服务器交互
    vscode Prettier配置
    MySQL主/从-主/主集群安装部署
    Redis的安装与基本使用
    【Rust日报】2023-09-25 Rust + Wasm 是 AGI 的语言吗
    全球133种语言自动翻译mishop大米外贸商城系统
    MySQL常见锁探究
    序列化方式介绍和性能比较 (kryo fastjson hessian jdk)
    unix:///var/tmp/supervisor.sock no such file
    关于springboot的优雅停机和健康检查配置(用于k8s服务重启)
  • 原文地址:https://blog.csdn.net/yang2330648064/article/details/126212246