fwrite函数的原型如下:
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
代码示例:
//二进制的读写 #include <stdio.h> struct S { char arr[10]; int num; float f; }; int main() { struct S s = { "zhangjoy",710,5.2f }; //以二进制的形式写 FILE* pf = fopen("test.txt", "w"); if (pf == NULL) { perror("fopen"); return 1; } //写文件 fwrite(&s, sizeof(struct S), 1, pf); //关闭文件 fclose(pf); pf = NULL; return 0; }
输出结果:
fread函数的原型如下:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
代码示例:
//二进制的读写 #include <stdio.h> struct S { char arr[10]; int num; float f; }; int main() { struct S s = { 0 }; //以二进制的形式读 FILE* pf = fopen("test.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } //读文件 fread(&s, sizeof(struct S), 1, pf); //打印 printf("%s %d %f", s.arr, s.num, s.f); //关闭文件 fclose(pf); pf = NULL; return 0; }
输出结果:
1.对比一组函数
scanf / fscanf / sscanf
printf / fprintf / sprintf
sprintf函数的原型如下:
int sprintf ( char * str, const char * format, ... );
代码示例:
#include <stdio.h> struct S { char arr[10]; int age; float f; }; int main() { struct S s = { "zhangjoy",23,5.2f }; char buf[100] = { 0 }; //sprintf函数将格式化的数据转化成字符串 sprintf(buf, "%s %d %f", s.arr, s.age, s.f); printf("%s\n", buf); return 0; }
输出结果:
sscanf函数的原型如下:
int sscanf ( const char * s, const char * format, ...);
代码示例:
#include <stdio.h> struct S { char arr[10]; int age; float f; }; int main() { struct S s = { "zhangjoy",23,5.2f }; struct S temp = { 0 }; char buf[100] = { 0 }; //sprintf函数将格式化的数据转化成字符串 sprintf(buf, "%s %d %f", s.arr, s.age, s.f); printf("%s\n", buf); //从字符串buf中还原出一个结构体数据 sscanf(buf, "%s %d %f", temp.arr, &(temp.age), &(temp.f)); printf("%s %d %f\n", temp.arr, temp.age, temp.f); return 0; }
输出结果:
文件的随机读写
1.fseek
如果我们向随机读写文件中的数据,是否可以呢?答案是可以的,我们需要借助一个函数fseek,它可以根据文件指针的位置和偏移量来定位文件指针,其函数原型如下:
int fseek ( FILE * stream, long int offset, int origin );
SEEK_CUR //文件指针目前的位置- SEEK_END//文件末尾的位置
- SEEK_SET//文件起始的位置
代码示例:
#include <stdio.h> int main() { FILE* pf = fopen("test.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } //读取文件 int ch = 0; while ((ch = fgetc(pf)) != EOF) { printf("%c", ch);//zhangjoy //此时文件指针pf指向y后面的位置 } //调整文件指针 fseek(pf, -1, SEEK_CUR); ch = fgetc(pf); printf("\n%c\n", ch);//y fseek(pf, -1, SEEK_END); ch = fgetc(pf); printf("%c\n", ch);//y fseek(pf, 0, SEEK_SET); while ((ch = fgetc(pf)) != EOF) { printf("%c", ch);//zhangjoy } //关闭文件 fclose(pf); pf = NULL; return 0; }
输出结果:
2.ftell
返回文件指针相对于起始位置的偏移量
函数原型如下:
long int ftell ( FILE * stream );
代码示例:
#include <stdio.h> int main() { FILE* pf = fopen("test.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } //读取文件 int ch = 0; //调整文件指针 //zhangjoy fseek(pf, 0, SEEK_END); int ret = ftell(pf); printf("%d\n", ret);//8 //关闭文件 fclose(pf); pf = NULL; return 0; }
输出结果:
3.rewind
让文件指针的位置回到文件的起始位置
rewind函数的原型如下:
void rewind ( FILE * stream );
代码示例:
#include <stdio.h> int main() { FILE* pf = fopen("test.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } //读取文件 int ch = 0; //调整文件指针 //让文件指针指向文件末尾的位置 fseek(pf, 0, SEEK_END); //让文件指针pf回到起始位置 rewind(pf); while ((ch = fgetc(pf)) != EOF) { printf("%c", ch);//zhangjoy } //关闭文件 fclose(pf); pf = NULL; return 0; }
输出结果:
文本文件和二进制文件
在C语言中,按数据存储的编码形式,数据文件可分为文本文件和二进制文件。文本文件是以字符的ASCII码值进行存储与编码的文件,其文件的内容是字符。二进制文件是存储二进制数据的文件。
例如对于整数1234,如果存放到文本文件中,文件内容将包含四个字符:49、50、51、52,它们分别是'1'、'2'、'3'、'4'的ASCII码值;如果把整数1234存放到二进制文件中去,文件内容将为1234对应的二进制数0x04D2,共两个字节。对于具体的数据选择哪一类文件进行存储,应该由需要解决的问题来决定,并在程序的一开始就定义好。
#include <stdio.h> int main() { int a = 10000; FILE* pf = fopen("test.txt", "wb"); if (pf == NULL) { perror("fopen"); return 1; } fwrite(&a, sizeof(int), 1, pf);//二进制的形式写到文件中 fclose(pf); pf = NULL; return 0; }
文件读取结束的判定
1.被错误使用的feof
feof函数的原型如下:
int feof ( FILE * stream );
牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件结尾结束。
1. 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
例如:
fgetc 判断是否为 EOF .
fgets 判断返回值是否为 NULL .
2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
例如:
fread判断返回值是否小于实际要读的个数。
代码示例1:
#include <stdio.h> int main() { FILE* pfread = fopen("test.txt", "r"); if (pfread == NULL) { return 1; } FILE* pfwrite = fopen("test2.txt", "w"); if (pfwrite == NULL) { perror("pfwrite"); fclose(pfread); pfread = NULL; return 1; } //文件打开成功 //读文件 int ch = 0; while ((ch = fgetc(pfread)) != EOF) { //写文件 fputc(ch, pfwrite); } //关闭文件 fclose(pfread); pfread = NULL; fclose(pfwrite); pfwrite = NULL; return 0; }
输出结果:
ferror函数的原型如下:
int ferror ( FILE * stream );
代码示例2:
#include <stdio.h> int main() { FILE* pfread = fopen("test.txt", "r"); if (pfread == NULL) { return 1; } FILE* pfwrite = fopen("test2.txt", "w"); if (pfwrite == NULL) { perror("pfwrite"); fclose(pfread); pfread = NULL; return 1; } //文件打开成功 //读文件 int ch = 0; while ((ch = fgetc(pfread)) != EOF) { //写文件 fputc(ch, pfwrite); } if (feof(pfread)) { printf("遇到文件介绍标志,文件正常结束\n"); } else if (ferror(pfread)) { printf("文件读取失败结束\n"); } //关闭文件 fclose(pfread); pfread = NULL; fclose(pfwrite); pfwrite = NULL; return 0; }
输出结果:
文件缓冲区
ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。
下面的一段代码,可以证明文件缓冲区的存在。
代码示例:
#include <stdio.h> #include <windows.h> int main() { FILE* pf = fopen("test.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; }
输出结果:
这里可以得出一个结论:因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。如果不做,可能导致读写文件的问题。
以上就是本篇博客的全部内容了,如果大家觉得有收获的话,可以点个赞支持一下!
结语
每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根。