前言
文接上回,我们在文件操作(上)里讲到了C语言中对文件的顺序读写。如果说,我们不想按照文件原本的顺序来对它进行读写(即,随机读写文件内容),又该如何操作呢?
请随我一同进入本篇文章中,我将为你细致的讲解C语言中的文件操作。
一、文件的随机读写
1.如何进行随机读写
通过对文件指针的使用,改变文件的读写的顺序,就能实现文件的随机读写
2.相关函数(含例子)
1.fseek函数
功能:根据文件指针的位置和偏移量来定位文件指针
其中,偏移量的起始位置可以是一下几种情况:
SEEK_SET文件的起始位置
SEEK_CUR当前文件指针所指向的位置
SEEK_END文件的末尾位置
例子
/* fseek example */ #include <stdio.h> int main () { FILE * pFile; pFile = fopen ( "example.txt" , "wb" ); fputs ( "This is an example." , pFile ); fseek ( pFile , 9 , SEEK_SET ); fputs ( " sam" , pFile ); fclose ( pFile ); return 0; }
2.ftell函数
功能:返回文件指针相对于起始位置的偏移量。
例子
/* 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; }
3.rewind函数
功能:将文件指针的位置返回文件的起始位置
例子
/* rewind example */ #include <stdio.h> int main() { int n; FILE * pFile; char buffer[27]; pFile = fopen("myfile.txt", "w+"); for (n = 'A'; n <= 'Z'; n++) fputc(n, pFile); rewind(pFile); fread(buffer, 1, 26, pFile); fclose(pFile); buffer[26] = '\0'; puts(buffer); return 0; }
二、文件读取结束的判定
我们主要进行的是判断文件的读取是正常结束还是异常结束的。
1.判定结束的相关函数
1.feof函数
feof不是用来判断文件的读取是否结束,它是用于判断文件读取是否正常结束
功能:feof函数,判断文件是正常结束(读到文件末尾,导致文件读取结束)
2.ferror函数
功能:ferror函数,判断文件是异常结束(读取文件内容失败,导致文件读取结束)
注意:一般情况下feof函数和ferror函数配套使用。
2.不同类型文件
实际上,我们想要判断文件是否为正常结束,不但需要了解这两种函数,还要了解不同类型文件的结束都有什么特点。
首先带大家了解一下文本文件和二进制文件
1.文本文件和二进制文件
1.文本文件:数据在文件中以ASCII字符形式存储
2.二进制文件:数据在文件中以二进制形式存储
3.数据类型不同,存储方式也有差异:
(1)字符以ASCII码形式存储;
(2)数值既可以用二进制形式存储,又可以用ASCII码形式存储。
2.不同文件的所判断的返回值(文件结束的特点)
1.文本文件:
由于函数不同,返回值不同:
(1)用函数fgetc,判断返回值是否为EOF;
(2)用函数fgets,判断返回值是否为NULL;
2.二进制文件:
用函数fread,判断返回值是否小于实际要读的值(fread函数返回值是实际读取到的元素个数)。
3.相关函数(与文件的返回值有关)
1.函数fgetc
功能及返回值:该函数以无符号char强制转换为int的形式返回读取的字符,当文件读取失败或者遇到文件结束都会返回EOF。
所以,可以用fgetc函数判断返回值是否为EOF。
2.函数fgets
如果读取字符成功,该函数返回存储数据的首地址;
如果达到文件末尾或者没有读取到任何字符,str指向的数组内容不变,返回一个空指针NULL;
如果读取时发生错误,读取结束,返回一个空指针NULL。
所以,可以用函数fgets判断返回值是否为NULL。
3.fread函数
fread函数返回值是实际读取到的元素个数(如果实际取回值的个数小于所想要取回的值的个数,就说明文件读取结束了)
3.例子
1.文本文件
#include <stdio.h> #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)) puts("I/O error when reading"); else if (feof(fp)) puts("End of file reached successfully"); fclose(fp); }
2.二进制文件
#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); }
三、文件缓冲区
1.概念介绍
系统会自动在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。
内存中数据传输到磁盘的过程与缓冲区的关系,如图所示:
文字解释:从内存向磁盘输出的数据或者从磁盘文件读取的数据,会先送到内存中的缓冲区。当缓冲区内数据放满或者刷新缓冲区时,缓冲区内数据才会被传出缓冲区,进一步被输入或输出。(缓冲区的大小根本由编译器决定)
2.相关函数
1.fflush函数
功能:冲洗流中的信息,强迫将缓冲区的数据写入文件指针指定的文件中(即,刷新文件缓冲区)
2. fclose函数
关于·fclose的相关概念在文件(上)中已经介绍过所以这里就不再赘述了。但是请注意以下内容:
在用fclose函数关闭文件时,也会刷新缓冲区(所以,如果打开文件,但是不关闭文件,就有可能会丢失数据)
3.具体例子
#include <stdio.h> #include <windows.h> //VS2013 WIN10环境测试 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语言中文件的相关操作,主要包括有文件的随机读写、文件读取结束原因的判定,介绍了相关的函数和具体如何使用这些函数,同时还补充了关于文件缓冲区的相关知识。
本文的作者也只是一个正在学习C语言等编程知识的萌新,若这篇文章中有哪些不正确的内容,请在评论区向作者指出(也可以私信作者),欢迎大佬们指点,也欢迎其他正在学习C语言的萌新和作者进行交流。
最后,如果本篇文章对你有所启发的话,也希望可以支持支持作者,后续作者也会定期更新学习记录。谢谢大家!