文件的随机读写
文件指针在读文件时,定位文件内容不断发生变化,如果不想顺序读取呢?可以进行文件随机读写
fseek
根据文件指针的位置和偏移量来定位文件指针
int fseek ( FILE * stream, long int offset, int origin );//成功则返回0,否则返回非0
test.data中存放的是abcdef
1. #define _CRT_SECURE_NO_WARNINGS 1 2. #include<stdio.h> 3. int main() 4. { 5. FILE* pf = fopen("test.data", "r"); 6. if (pf == NULL) 7. { 8. perror("fopen"); 9. return 1; 10. } 11. 12. //读取文件 13. int ch = fgetc(pf); 14. printf("%c\n", ch);//a 15. 16. //调整文件指针 17. fseek(pf, 1, SEEK_CUR);//当前指针指向b,向后偏移一位,指向c 18. 19. ch = fgetc(pf); 20. printf("%c\n", ch);//c 21. 22. fclose(pf); 23. pf = NULL; 24. return 0; 25. }
ctrl+F5运行,结果如下所示:
ftell
返回文件指针相对于起始位置的偏移量
long int ftell ( FILE * stream );//若成功则返回指针位置的值
1. #define _CRT_SECURE_NO_WARNINGS 1 2. #include<stdio.h> 3. int main() 4. { 5. FILE* pf = fopen("test.data", "r"); 6. if (pf == NULL) 7. { 8. perror("fopen"); 9. return 1; 10. } 11. 12. //读取文件 13. int ch = fgetc(pf); 14. printf("%c\n", ch);//a 15. 16. ch = fgetc(pf); 17. printf("%c\n", ch);//b 18. 19. ch = fgetc(pf); 20. printf("%c\n", ch);//c 21. 22. //调整文件指针 23. fseek(pf, -2, SEEK_CUR); 24. 25. ch = fgetc(pf); 26. printf("%c\n", ch);//b 27. 28. //计算指针相对于起始位置的偏移 29. int ret = ftell(pf); 30. printf("%d\n", ret); 31. 32. fclose(pf); 33. pf = NULL; 34. return 0; 35. }
ctrl+F5运行,结果如下所示:
rewind
让文件指针的位置回到文件的起始位置
void rewind ( FILE * stream );
1. #define _CRT_SECURE_NO_WARNINGS 1 2. #include<stdio.h> 3. int main() 4. { 5. FILE* pf = fopen("test.data", "r"); 6. if (pf == NULL) 7. { 8. perror("fopen"); 9. return 1; 10. } 11. 12. //读取文件 13. int ch = fgetc(pf); 14. printf("%c\n", ch);//a 15. 16. ch = fgetc(pf); 17. printf("%c\n", ch);//b 18. 19. ch = fgetc(pf); 20. printf("%c\n", ch);//c 21. 22. //调整文件指针 23. fseek(pf, -2, SEEK_CUR); 24. 25. ch = fgetc(pf); 26. printf("%c\n", ch);//b 27. 28. //计算指针相对于起始位置的偏移 29. int ret = ftell(pf); 30. printf("%d\n", ret); 31. 32. //让文件指针回到起始位置 33. rewind(pf); 34. ch = fgetc(pf); 35. printf("%c\n", ch);// 36. 37. fclose(pf); 38. pf = NULL; 39. return 0; 40. }
ctrl+F5运行,结果如下所示:
文本文件和二进制文件
根据数据的组织形式,数据文件被称为文本文件或者二进制文件:数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件;如果要求在外存上以ASCII码的形式存储,则需要在存储前转换,以ASCII字符的形式存储的文件就是文本文件。
一个数据在内存中是怎么存储的呢?
字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节,31 30 30 30 30),而二进制形式输出,则在磁盘上只占4个字节(10 27 00 00)
1. #define _CRT_SECURE_NO_WARNINGS 1 2. #include<stdio.h> 3. int main() 4. { 5. int a = 10000; 6. FILE* pf = fopen("test.data", "wb"); 7. if (pf == NULL) 8. { 9. perror("fopen"); 10. return 1; 11. } 12. 13. //写文件 14. fwrite(&a, sizeof(int), 1, pf); 15. return 0; 16. }
VS2019解决方案-源文件-添加-现有项,打开test.data文件
右击文件名-打开方式-二进制编辑器-确定
二进制打开文本文件:
文本读取结束的判定
feof
feof用于判断当文件读取结束的时候,是读取失败结束,还是遇到文件尾结束。
int feof ( FILE * stream );//返回非0则遇到文件尾结束,返回0则读取失败结束
所以使用feof时,文件一定读取结束了,因此不能用feof的返回值判断文件是否结束。
新建test1.data文本,向test.data里面存放的内容:
将test.data中的内容写入到test1.data中:
1. #define _CRT_SECURE_NO_WARNINGS 1 2. #include<stdio.h> 3. 4. int main() 5. { 6. FILE* pfread = fopen("test.data", "r"); 7. if (pfread == NULL) 8. { 9. return 1; 10. } 11. FILE* pfwrite = fopen("test1.data", "w"); 12. if (pfread == NULL) 13. { 14. fclose(pfread); 15. pfread = NULL; 16. return 1; 17. } 18. 19. //文件打开成功 20. //读写文件 21. int ch = 0; 22. while ((ch = fgetc(pfread)) != EOF) 23. { 24. //写文件 25. fputc(ch, pfwrite); 26. } 27. 28. if (feof(pfread)) 29. { 30. printf("遇到文件结束标志,文件正常结束\n"); 31. } 32. else if(ferror(pfread)) 33. { 34. printf("文件读取失败结束\n"); 35. } 36. 37. //关闭文件 38. fclose(pfread); 39. pfread = NULL; 40. fclose(pfwrite); 41. pfwrite = NULL; 42. 43. return 0; 44. }
ctrl+F5运行,结果如下:
且test.data的内容已经全部拷贝到test1.data中:
由此可以看出 ,feof返回非0,且遇到文件尾结束的。
文本文件读取结束和二进制文件读取结束的判断不同:
(1)文本文件读取是否结束,判断返回值是否为EOF(fgetc),或NULL(fgets)。上面代码就是判断文本文件读取是否结束。
fgetc函数在读取结束的时候,会返回EOF;正常读取的时候,返回的是读取到的字符的ASCII码值。
fgets函数在读取结束的时候,会返回NULL,正常读取的时候,返回存放字符串的空间起始地址。
(2)二进制文件的读取结束判断,判断返回值是否小于实际要读的个数
fread函数在读取的时候,返回的是实际读取到的完整元素的个数。如果发现读取到的完整元素的个数小于指定的元素个数,这就是最后一次读取了。
文件缓冲区
ANSIC 标准采用“缓冲文件系统”处理数据文件,缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。
下面代码可以证明缓冲区的存在:
1. #define _CRT_SECURE_NO_WARNINGS 1 2. #include<stdio.h> 3. #include<windows.h> 4. int main() 5. { 6. FILE* pf = fopen("test.data", "w"); 7. fputs("abcdef", pf);//先将代码放在输出缓冲区 8. 9. printf("睡眠10秒-已经写数据了,打开test.data文件,发现文件没有内容\n"); 10. Sleep(10000); 11. 12. printf("刷新缓冲区\n"); 13. fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘) 14. 15. printf("再睡眠10秒-此时,再次打开test.data文件,文件有内容了\n"); 16. Sleep(10000); 17. 18. fclose(pf); 19. //注:fclose在关闭文件的时候,也会刷新缓冲区 20. pf = NULL; 21. 22. return 0; 23. }
ctrl+F5运行,打开test.data,文件为空
过10秒后,打开test.data,发现内容已经写入进去了,是从缓冲区写到文件的。