前言:
在前几个章节讲解字符读写函数,字符串读写函数,格式化输入输出函数以及scanf,fscanf,sscanf,和s(f)printf。
在本章讲解文件随机读取
一·文件的随机读取
1·fseek
函数
fseek
函数用于定位文件内容的光标,通过偏移量从文件开头、当前位置或文件尾开始计算光标位置。其函数原型如下:
int fseek(FILE *stream, long offset, int whence);
stream
:文件指针。offset
:位移量,表示移动的字节数。whence
:起始点,可以是以下三个值之一:SEEK_SET
:文件开头。SEEK_CUR
:当前位置。SEEK_END
:文件尾。
例子:
#include <stdio.h>
int main()
{
FILE* fp = fopen("example.txt", "w+");
if (fp == NULL)
{
perror("打开文件失败");
return 1;
}
// 写入一些内容
fputs("这是C语言文件操作示例", fp);
// 移动到第6个字节处(跳过"这是C语")
fseek(fp, 9, SEEK_SET);
// 从当前位置开始写入
fputs("编程", fp);
// 关闭前重置指针位置并输出内容
rewind(fp);
char buffer[100];
fgets(buffer, sizeof(buffer), fp);
printf("修改后的内容: %s\n", buffer); // 输出: 这是C语言编程操作示例
fclose(fp);
return 0;
}
2·ftell
函数
ftell
函数返回当前文件光标到文件开头的偏移量,用于计算文件大小。其函数原型如下:
long ftell(FILE *stream);
例子:
#include <stdio.h>
int main()
{
FILE* fp = fopen("data.txt", "r");
if (fp == NULL)
{
perror("打开文件失败");
return 1;
}
// 获取初始位置
long pos = ftell(fp);
printf("初始位置: %ld\n", pos); // 0
// 读取一些数据
char ch;
for (int i = 0; i < 5; i++)
{
ch = fgetc(fp);
if (ch == EOF) break;
printf("%c", ch);
}
// 获取当前位置
pos = ftell(fp);
printf("\n当前位置: %ld\n", pos); // 5
fclose(fp);
return 0;
}
3·rewind
函数
rewind
函数将文件中的指针位置重置到文件开头,便于重新读写。其函数原型如下:
void rewind(FILE *stream);
例子:
#include <stdio.h>
int main()
{
FILE* fp = fopen("test.txt", "r+");
if (fp == NULL)
{
perror("打开文件失败");
return 1;
}
// 读取并显示第一行
char line[100];
fgets(line, sizeof(line), fp);
printf("第一行: %s", line);
// 重置到文件开头
rewind(fp);
// 再次读取第一行
fgets(line, sizeof(line), fp);
printf("再次读取第一行: %s", line);
fclose(fp);
return 0;
}
二·文件读取结束的判断
在进行文件读取时,需要判断何时到达文件末尾或发生错误。C语言提供了feof
和ferror
函数来帮助我们完成这一任务。
1·feof
函数
feof
函数用于判断文件是否处于结束位置。需要注意的是,feof
函数不能直接用于判断文件是否读取结束,而是在读取操作之后使用,以确定读取结束的原因是否是遇到文件尾。其函数原型如下:
int feof(FILE *stream);
例子:
#include <stdio.h>
int main()
{
FILE* fp = fopen("numbers.txt", "r");
if (fp == NULL)
{
perror("打开文件失败");
return 1;
}
int num;
printf("读取到的数字:\n");
while (1)
{
fscanf(fp, "%d", &num);
if (feof(fp))
{
printf("\n已到达文件末尾\n");
break;
}
printf("%d ", num);
// 检查错误
if (ferror(fp))
{
perror("读取错误");
break;
}
}
fclose(fp);
return 0;
}
2·ferror
函数
ferror
函数用于检查文件读写是否出错。其函数原型如下:
int ferror(FILE *stream);
例子:
#include <stdio.h>
int main()
{
FILE *fp = fopen("nonexistent.txt", "r");
if (fp == NULL)
{
perror("打开文件失败");
return 1;
}
// 故意制造错误(尝试写入只读模式打开的文件)
fputc('A', fp);
if (ferror(fp))
{
printf("检测到错误!\n");
perror("错误详情");
// 清除错误标志
clearerr(fp);
printf("错误标志已清除\n");
if (!ferror(fp))
{
printf("现在没有错误\n");
}
}
fclose(fp);
return 0;
}
3. 判断文件结束的原因示例
通过feof
和ferror
函数结合使用,可以判断文件读取是否正常或因错误而结束。以下是一些常见的判断方法:
-
文本文件是否读取结束:
- 判断函数
fgetc
的返回值是否为EOF
。 - 判断函数
fgets
的返回值是否为NULL
。
- 判断函数
-
二进制文件是否读取结束:
- 判断函数
fread
返回的实际读取元素个数是否小于预期值。
- 判断函数
示例代码如下:
#include <stdio.h>
int main() {
char arr[20];
FILE* pf = fopen("test.txt", "r");
if (pf == NULL) {
perror("fopen");
return 1;
}
fgets(arr, 20, pf);
printf("%s\n", arr);
if (feof(pf)) {
printf("文件正常读取结束\n");
}
if (ferror(pf)) {
printf("文件错误读取结束\n");
perror("读取失败原因");
}
fclose(pf);
return 0;
}
三·文件缓冲区
文件缓冲区是ANSIC标准中采用的“缓冲文件系统”,用于在内存中为程序中每个正在使用的文件开辟一块缓冲区,以提高数据读写效率。当缓冲区装满或文件被关闭时,缓冲区中的数据会自动刷新并写入文件。fflush
函数可以随时刷新缓冲区,使缓冲区中的数据立即写入文件。
1. 缓冲区的工作原理
- 全缓冲:当缓冲区满时,数据被刷新到磁盘。
- 行缓冲:当遇到换行符时,数据被刷新到磁盘。
- 无缓冲:数据直接写入磁盘,不使用缓冲区。
2. fflush
函数
fflush
函数用于刷新指定文件流的输出缓冲区。其函数原型如下:
int fflush(FILE *stream);
如果stream
为NULL
,则刷新所有打开的输出流。
3. 示例代码
#include <stdio.h>
int main() {
FILE* pf = fopen("test.txt", "w");
if (pf == NULL) {
perror("fopen");
return 1;
}
fprintf(pf, "Hello, World!\n");
fflush(pf); // 刷新缓冲区
fclose(pf);
return 0;
}
总结:
本章节详细介绍了C语言中文件的随机读取、文件读取结束的判定以及文件缓冲区
通过使用fseek
、ftell
和rewind
函数,可以实现文件的随机访问;通过feof
和ferror
函数,可以准确判断文件读取的状态;而文件缓冲区则通过在内存中暂存数据来提高文件操作的效率。
本章结束了!!!
我们下章再见!!