⭐️⭐️ fread
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
🔷举个栗子:
struct S { int n; double d; char name[10]; }; int main() { struct S s = { 0}; FILE* pf = fopen("F:\\test.txt", "wb"); //打开文件 if (pf == NULL) { perror("fopen");//打印错误信息 } fread(&s, sizeof(struct S), 1, pf); printf("%d %lf %s\n", s.n, s.d, s.name); fclose(pf); pf = NULL; return 0; }
⭐️⭐️ fwrite
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
🔷举个栗子:
struct S { int n; double d; char name[10]; }; int main() { struct S s = { 100,3.14,"zhuzhu"}; FILE* pf = fopen("F:\\test.txt", "wb"); //打开文件 if (pf == NULL) { perror("fopen");//打印错误信息 } fwrite(&s, sizeof(s), 1, pf); fclose(pf); pf = NULL; return 0; }
🔷在文件中储存的是二进制信息,显示出来是乱码的,虽然我们读不懂,但是计算机能够读懂它。
🔵🔵🔵那么到目前为止我们就学了三组相似类型的printf和scanf,来总结一下:
⭐️⭐️ fseek
int fseek ( FILE * stream, long int offset, int origin );
注:参数origin
:
🔷举个栗子:
/* fseek example */ #include <stdio.h> int main () { FILE * pFile; pFile = fopen ( "example.txt" , "wb" );`在这里插入代码片` fputs ( "This is an apple." , pFile ); fseek ( pFile , 9 , SEEK_SET ); fputs ( " sam" , pFile ); fclose ( pFile ); return 0; }
结果:
This is a sample. //当这段代码运行成功之后,example.txt文本里就会包含这句话
⭐️⭐️ ftell
long int ftell ( FILE * stream );
🔷举个栗子:
/* ftell example : getting size of a file */ #include <stdio.h> int main () { FILE * pFile; long size; pFile = fopen ("myfile.txt","rb"); if (pFile==NULL) perror ("Error opening file"); else { fseek (pFile, 0, SEEK_END); // non-portable size=ftell (pFile); fclose (pFile); printf ("Size of myfile.txt: %ld bytes.\n",size); } return 0; }
结果:此代码以字节为单位打印myfile.txt
的大小,因为SEEK_END
使指针指向文件末尾。
⭐️⭐️ rewind
void rewind ( FILE * stream );
🔷举个栗子:
从键盘输入一行字符,追加写入到一个文件中,再把该文件内容读出显示在屏幕上。
#include<stdio.h> int main() { FILE *fp; char ch; if((fp=fopen("C:\\Users\\dell\\Desktop\\abc.txt","ab+"))==NULL) { printf("\nCannot open file\nstrike any key exit\n"); getchar(); return 1; } printf("input a string:\n"); ch=getchar(); while(ch!='\n') { fputc(ch,fp); ch=getchar(); } rewind(fp); ch=fgetc(fp); while(ch!=EOF) { putchar(ch); ch=fgetc(fp); } fclose(fp); return 0; }
rewind(fp);
每输入一个字符,文件内部位置指针向后移动一个字节。写入完毕,该指针已指向文件末尾, 如果要把文件从头读出,须把指针移到文件头,利用rewind()
函数。
🔷三、文件结束判断与缓冲
1. 文件读取结束判断
⭐️⭐️ feof
int feof ( FILE * stream );
名称 | 详情 |
头文件 | stdio.h |
返回值 | 文件结束,则返回非0值,否则返回0 |
参数stream |
目标文件指针 |
作用 | 当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。 |
🔷被错误使用的feof
应当记住:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。
而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。
文本文件读取是否结束,应该判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
例如:
fgetc 判断是否为 EOF
fgets 判断返回值是否为 NULL
二进制文件的读取结束判断,是通过判断返回值是否小于实际要读的个数。
例如:
fread判断返回值是否小于实际要读的个数。
🔷举个栗子(文本文件的例子):
#include <stdlib.h> int main(void) { int c; // 注意:int,非char,要求处理EOF FILE* fp = fopen("test.txt", "r"); if(!fp) { perror("File opening failed"); return EXIT_FAILURE; } //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环 { putchar(c); } //判断是什么原因结束的 if (ferror(fp))//如果ferror返回非01值,说明文件读取发生错误 puts("I/O error when reading"); else if (feof(fp))//如果feof返回非0说明有读到文件末尾 puts("End of file reached successfully"); fclose(fp); }
🔷举个栗子(二进制文件的例子):
#include <stdio.h> enum { SIZE = 5 }; int main(void) { double a[SIZE] = {1.,2.,3.,4.,5.}; FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式 fwrite(a, sizeof *a, SIZE, fp); // 写 double 的数组 fclose(fp); double b[SIZE]; fp = fopen("test.bin","rb"); size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 读 double 的数组 if(ret_code == SIZE) { puts("Array read successfully, contents: "); for(int n = 0; n < SIZE; ++n) printf("%f ", b[n]); putchar('\n'); } else { // error handling if (feof(fp)) printf("Error reading test.bin: unexpected end of file\n"); else if (ferror(fp)) { perror("Error reading test.bin"); } } fclose(fp); }
🔷总结:
feof的用途:是当文件读取结束之后,判断是不是遇到文件末尾而结束的。
ferror的用途:是当文件读取结束之后,判断是不是遇到错误后读取结束的。
2. 文件缓冲区
ANSIC 标准采用“缓冲文件系统”处理的数据文件的。
所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。
从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。
如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。
缓冲区的大小根据C编译系统决定的。
⭐️⭐️ fflush
int fflush(FILE *stream);
🔷举个栗子:
#include <windows.h> //VS2013 WIN10环境测试 int main() { FILE*pf = fopen("test.txt", "w"); fputs("abcdef", pf);//先将代码放在输出缓冲区 printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n"); Sleep(10000);//这里是1000毫秒,就是10秒 printf("刷新缓冲区\n"); fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘) //注:fflush 在高版本的VS上不能使用了 printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n"); Sleep(10000); fclose(pf); //注:fclose在关闭文件的时候,也会刷新缓冲区 pf = NULL; return 0; }
结论:
因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。
如果不做,可能导致读写文件的问题。