C语言进阶第十课 --------文件的操作-2
https://developer.aliyun.com/article/1498898
二进制输出函数
上面的函数是使用在所有输入流和输出流的函数(包含有标准输入、输出流和文件流),一般我们只是使用整形或者字符来写入和输出,只能解决一些,但是如果遇见二进制就不一定行了,下面介绍两个函数用于二进制文件的读写操作
ptr 是指向要写入文件的数据的指针,size 是每个数据项的大小(以字节为单位),count 是要写入的数据项的数量,stream 是指向要写入的文件的指针。
返回成功写入的元素总数。
int main() { FILE *file = fopen("./test.txt", "wb"); if (file == NULL) { perror("fopen"); return 1; } int arr[10] = {65,67,68,69,70,71,72,73,74}; fwrite(arr, 4, 9, file); fclose(file); file = NULL; return 0; }
二进制输入函数
ptr 是指向要存储读取数据的内存区域的指针,size 是每个数据项的大小(以字节为单位),count 是要读取的数据项的数量,stream 是指向要读取的文件的指针。
返回成功读取的元素总数。
#include<stdio.h> #include<stdlib.h> int main() { FILE *file = fopen("./test.txt", "rb"); if (file == NULL) { perror("fopen"); return 1; } int arr[5]; fread(arr, 4, 5, file); fclose(file); file = NULL; return 0; }
sprintf(将格式化的数据转换成字符串)
sprintf 是 C 语言标准库中的一个函数,用于将格式化的数据写入字符串。它的使用方式与 printf 类似,但是 sprintf 将输出写入到指定的字符串中,而不是标准输出(屏幕)简单理解就是把屏幕换成字符串中
str 是指向输出字符串的指针,format 是格式化字符串,后面的 … 表示可变参数列表,用于填充格式化字符串中的占位符。sprintf 的返回值是输出到字符数组中的字符数(不包括空字符)
#include<stdio.h> #include<stdlib.h> int main() { char arr[10] = "123456789"; char arr1[10] = "1111111"; int a = 100; sprintf(arr, "%s", arr1); sprintf(arr, "%d", a); return 0; }
就是把arr1的数据写入到arr
将字符串转换成格式化的数据(sscanf)
str 是要读取的字符串,format 是格式化字符串,后面的 … 表示可变参数列表,用于接收读取到的数据。sscanf 的返回值是成功读取并赋值的参数个数
#include<stdio.h> #include<stdlib.h> #include<math.h> int main() { char arr[] = "1000 100 100"; int arr1[5]; int b; sscanf(arr, "%d %d %d", arr1, arr1 + 1, arr1 + 2); return 0; }
把arr的数据以int类型写入到arr1中
文件的随机读写
fseek(控制光标的位置)
其中,stream 是一个指向文件的指针,offset 是要定位的偏移量(左负右正),origin 是定位的起始位置。origin 可以取以下值之一:
SEEK_SET:从文件开头开始计算偏移量。
SEEK_CUR:从当前位置开始计算偏移量。
SEEK_END:从文件末尾开始计算偏移量。
fseek 的返回值为 0 表示成功,非零值表示失败。
#include<stdio.h> #include<stdlib.h> #include<math.h> int main() { FILE *file = fopen("./test.txt", "r+"); if (file == NULL) { perror("fopne"); return 1; } char a; char arr[5]; //读文件 a = fgetc(file); fseek(file, -1, SEEK_CUR);//当前位置向左移动 fgets(arr, 5, file); printf("%c\n", a); printf(arr); fclose(file); file = NULL; return 0; }
计算起始位置到当前位置的偏移量(ftell)
stream 是一个指向文件的指针。ftell 的返回值是当前文件指针相对于文件开头的偏移量,如果发生错误则返回 -1。
include<stdio.h> #include<stdlib.h> #include<math.h> int main() { FILE* file = fopen("./test.txt", "r"); if (file == NULL) { perror("fopen"); return 1; } char arr[10]; fgets(arr, 5, file); int a = ftell(file); printf("%d", a); fclose(file); file = NULL; return 0; }
让文件指针的位置回到文件的起始位置(rewind)
stream 是一个指向文件的指针。rewind 函数会将文件指针移动到文件的开头,相当于调用 fseek(stream, 0, SEEK_SET)。
include<stdio.h> #include<stdlib.h> #include<math.h> int main() { FILE* file = fopen("./test.txt", "r"); if (file == NULL) { perror("fopen"); return 1; } char arr[10]; fgets(arr, 5, file); rewind(file); int a = ftell(file); printf("%d", a); fclose(file); file = NULL; return 0; }
文件的介绍
根据数据的组织形式,数据文件被称为文本文件或者二进制文件。
数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节(VS2013测试)。
这张图是不使用二进制输入的结果
这张图就是二进制输入的结果,有小端存储
文件读取结束的判定
feof
这个函数不是用来判断文件是否结束的,很多人误以为这个使用判断文件是否结束的,这种是错误的
文件结束的情况是多种的,而feof函数是用来判断文件结束是否是读取到文件末尾而结束
检查文件结束指示器
如果设置了与流关联的文件结束指示符,则返回非零值。
否则,返回零。
简单理解就是,当文件遇见文件结束标准 就会返回非0值,否则就会返回0
#include<stdio.h> #include<stdlib.h> #include<math.h> int main() { FILE* pf = fopen("./test.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } FILE* pf1 = fopen("./test1.txt", "w"); if (pf1 == NULL) { perror("fopen"); return 1; } int ch = 0; while ((ch = fgetc(pf)) != EOF) { fputc(ch, pf1); } if (feof(pf)) { puts("正常文件结束\n"); } fclose(pf); pf = NULL; fclose(pf1); pf1 = NULL; return 0; }
perror用于输出文件相关的错误信息,而feof用于判断文件指针是否到达文件末尾。
perror主要用于处理文件操作中的错误,而feof主要用于控制文件读取的循环条件。
#include<stdio.h> #include<stdlib.h> #include<math.h> int main() { FILE* pf = fopen("./test.txt", "rb"); if (pf == NULL) { perror("fopen"); return 1; } int arr1[10] = { 0 }; int num = fread(arr1, sizeof * arr1, sizeof(arr1) / sizeof *arr1, pf); if (num == sizeof(arr1) / sizeof * arr1) { while (num) { printf("%d ", arr1[--num]); } } else { if (ferror(pf)) { puts("文件读取到错误\n"); } else if(feof(pf)) { printf("文件正常结束\n"); } } fclose(pf); pf = NULL; return 0; }
ferror用于检测文件操作函数是否发生了错误,而feof用于判断文件指针是否到达文件末尾。
ferror主要用于处理文件操作中的错误,而feof主要用于控制文件读取的循环条件。
文件缓冲区
ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的
文件缓冲区是在内存上的
输入输出流(Input/Output Stream)是指用于数据传输的抽象概念。在计算机中,输入流用于从外部获取数据,输出流用于向外部发送数据。输入流和输出流可以与不同的设备或资源进行交互,如键盘、文件、网络等。
缓冲区(Buffer)是用于临时存储数据的内存区域。在输入输出操作中,缓冲区通常与输入输出流相关联。当进行输入操作时,数据会先存储到输入流的缓冲区中;而进行输出操作时,数据会先存储到输出流的缓冲区中。缓冲区的存在可以提高输入输出的效率,减少对底层设备的频繁访问。
使用缓冲区的好处是可以批量处理数据,减少对底层设备的读写次数。当缓冲区被填满或达到一定条件时,数据会被一次性地写入或读取。这样可以提高性能和效率。缓冲区的大小通常是固定的,根据应用程序的需求进行设置。
在C语言中,标准库提供了一系列函数来进行输入输出操作,如fread、fwrite、fgets、fputs等。这些函数会自动将数据从缓冲区读取或写入到输入输出流中。同时,我们也可以使用fflush函数来手动刷新缓冲区,确保数据及时地写入或读取。
总结:
输入输出流用于数据传输,输入流用于获取数据,输出流用于发送数据。
缓冲区是临时存储数据的内存区域,与输入输出流相关联。
缓冲区可以提高输入输出操作的效率,减少对底层设备的频繁访问。
在C语言中,使用标准库函数进行输入输出操作,并自动将数据读取或写入到缓冲区中。
#include<stdio.h> #include<stdlib.h> #include<math.h> #include<windows.h> int main() { FILE* pf = fopen("./test1.txt", "w"); fputs("abcdef", pf);//先将代码放在输出缓冲区 printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n"); Sleep(10000); printf("刷新缓冲区\n"); fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘) //注:fflush 在高版本的VS上不能使用了 printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n"); Sleep(10000); fclose(pf); //注:fclose在关闭文件的时候,也会刷新缓冲区 pf = NULL; return 0; }
在缓冲区中要想写入数据到文件有两者方法
1.缓冲区满了或者刷新缓冲区会把数据写入到文件
2.程序结束,会把数据写入到文件