文件的随机读写
fseek
根据文件指针的位置和偏移量来定位文件指针。
例子:
int fseek ( FILE * stream, long int offset, int 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; }
fseek函数是C语言中的一个标准库函数,用于在文件中定位文件指针的位置。
它的原型如下:
int fseek(FILE *stream, long int offset, int whence);
其中,stream是一个指向要进行定位的文件的指针,offset是要设置的偏移量,表示距离whence位置的偏移量,whence表示相对于何处进行定位的标志。
whence参数可以取以下三个值:
SEEK_SET:从文件开头开始计算偏移量。
SEEK_CUR:从当前位置开始计算偏移量。
SEEK_END:从文件末尾开始计算偏移量。
fseek函数用于将文件指针定位到指定位置,以便进行后续的读取或写入操作。通过指定偏移量和whence参数,可以实现不同的定位需求,例如从文件开头处跳过固定长度的数据,或者从当前位置向后移动指定偏移量。
下面是一个使用fseek函数的示例:
#include <stdio.h> int main() { FILE *fp = fopen("example.txt", "r"); if (fp != NULL) { fseek(fp, 5, SEEK_SET); // 设置文件指针跳过前5个字节 char ch; fscanf(fp, "%c", &ch); printf("Character: %c\n", ch); fclose(fp); } return 0; }
在这个示例中,我们打开了一个名为"example.txt"的文件,并使用fseek函数将文件指针定位到距离文件开头5个字节处。然后,我们使用fscanf函数读取下一个字符,并将其输出到控制台。
假设文件中的内容为:“Hello, world!”,那么输出结果如下:
Character: ,
通过调用fseek函数进行文件定位,我们可以控制文件指针的位置,以便进行读取或写入操作。
ftell是C语言中的标准库函数,用于获取文件指针当前位置相对于文件起始位置的偏移字节数。它的原型如下:
long ftell(FILE *stream);
其中,stream是一个指向已打开文件的指针。
ftell函数返回一个long类型的值,表示当前位置相对于文件起始位置的偏移字节数。如果函数调用失败,它将返回-1。
下面是一个使用ftell函数的简单示例:
#include <stdio.h> int main() { FILE *fp = fopen("example.txt", "r"); if (fp != NULL) { // 获取文件指针位置 long position = ftell(fp); printf("Current position: %ld\n", position); fclose(fp); } return 0; }
在这个示例中,我们打开了一个名为"example.txt"的文件,并使用fopen函数创建了一个文件指针fp。然后,我们使用ftell函数获取当前文件指针的位置,并将其输出到控制台。
ftell函数通常与fseek函数联合使用,可以用来定位文件中的特定位置,并支持在文件中进行随机读写操作。
需要注意的是,ftell函数返回的偏移字节数类型是long,具体字节数的上限取决于编译环境中的long类型的大小。
rewind函数是C语言中的一个标准库函数,用于将文件指针重新定位到文件的起始位置。它的原型如下:
void rewind(FILE *stream);
其中,stream是一个指向要重新定位的文件的指针。
rewind函数将文件指针重新设置为文件的起始位置,以便重新读取文件或执行其他操作。
下面是一个使用rewind函数的简单示例:
#include <stdio.h> int main() { FILE *fp = fopen("example.txt", "r"); if (fp != NULL) { char ch; // 读取文件中的一个字符 fscanf(fp, "%c", &ch); printf("Character: %c\n", ch); // 将文件指针重新定位到文件起始位置 rewind(fp); // 再次读取文件中的一个字符 fscanf(fp, "%c", &ch); printf("Character: %c\n", ch); fclose(fp); } return 0; }
在这个示例中,我们打开了一个名为"example.txt"的文件,并使用fscanf函数读取文件中的一个字符,并将其输出到控制台。
然后,我们调用rewind函数将文件指针重新定位到文件的起始位置。
最后,我们再次使用fscanf函数读取文件中的一个字符,并将其输出到控制台。由于调用了rewind函数,所以我们重新读取到文件中的第一个字符。
文本文件和二进制文件
根据数据的组织形式,数据文件被称为文本文件或者二进制文件。
数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。
一个数据在内存中是怎么存储的呢?
字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而
二进制形式输出,则在磁盘上只占4个字节(VS2013测试)。
#include <stdio.h> int main() { int a = 10000; FILE* pf = fopen("test.txt", "wb"); fwrite(&a, 4, 1, pf);//二进制的形式写到文件中 fclose(pf); pf = NULL; return 0; }
文件读取结束的判定
被错误使用的feof
牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。
而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。
- 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
例如:
fgetc 判断是否为 EOF .
fgets 判断返回值是否为 NULL . - 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
例如:
fread判断返回值是否小于实际要读的个数。
文件缓冲区
ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。
#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语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。如果不做,可能导致读写文件的问题。
最后学完文件操作,小伙伴可以尝试一下将通讯录系统再次改造,把信息保存在桌面上的文本文档试一下吧!