1.文件的打开 (fopen)
1.1 基本介绍
在C语言中,所有的文件操作都是通过文件指针 (FILE*) 来进行的。要对文件进行操作,首先需要用 fopen 函数打开文件,并指定文件的路径和操作模式。
FILE fopen(const char filename, const char *mode);
1
filename: 要打开的文件名(可以包含路径,如 “C:\data\file.txt” 或者 “./file.txt”)。
mode: 文件打开模式,决定了你如何访问文件。
1.2 mode:文件打开模式
r 以只读模式打开文件。如果文件不存在,则返回 NULL。
a 以追加模式打开文件。如果文件不存在,则创建新文件;如果文件存在,则将数据写入到文件的末尾。
w 以写入模式打开文件。如果文件不存在,则创建新文件;如果文件存在,则清空文件内容。
r+ 以读写模式打开文件。文件必须存在,不会创建新文件。
w+ 以读写模式打开文件。如果文件不存在,则创建新文件;如果文件存在,则清空文件内容。
a+ 以读写模式打开文件。如果文件不存在,则创建新文件;如果文件存在,将写入的数据添加到文件末尾。
注意:
“r+” 可以进行读写操作,但不会创建新文件。
“w+” 会创建新文件或清空已有文件,然后进行读写操作。
“a+” 不会清空文件,可以在文件末尾添加数据,同时可以读取文件内容。
1.3 示例代码
FILE* fp = fopen("example.txt", "r");
if (fp == NULL)
{
perror("打开文件错误");
return -1;
}
1
2
3
4
5
6
fopen: 尝试以只读模式打开 “example.txt” 文件。
如果文件不存在或无法打开,fopen 返回 NULL,并打印错误信息。
1.4 错误处理
在打开文件时,建议立即检查返回值,以确保文件成功打开。
if (fp == NULL)
{
perror("打开文件错误");
return -1;
}
1
2
3
4
5
perror: 打印描述错误原因的消息,常用在 fopen、fread 等文件操作函数失败的情况下。
- 文件的读取
读取文件内容有多种方式,可以根据文件内容的格式选择适合的方法。
2.1 使用 fscanf 读取格式化数据
fscanf 函数用于从文件中读取格式化数据,类似于 scanf,只是它从文件读取而非标准输入。
int fscanf(FILE stream, const char format, ...);
1
stream: 文件指针(即 fopen 返回的 FILE*)。
format: 格式字符串,用于指定要读取的数据类型。
示例:
int age;
double salary;
fscanf(fp, "%d %lf", &age, &salary);
1
2
3
上述代码将从文件中读取一个整数和一个浮点数,并分别存储到 age 和 salary 变量中。
2.2 使用 fgets 读取一行文本
fgets 函数用于从文件中读取一行文本。 它读取到换行符或到达最大长度,或到文件末尾为止。
char fgets(char str, int n, FILE *stream);
1
str: 用于存储读取的字符串的字符数组。
n: 最大读取字符数(包括终止符 \0)。
stream: 文件指针。
示例:
char buffer[100];
if (fgets(buffer, 100, fp) != NULL)
{
printf("读入: %s", buffer);
}
1
2
3
4
5
该代码会读取文件中的一行内容,并将其存储在 buffer 中。
2.3 使用 fread 读取二进制数据
fread 用于从文件中读取二进制数据。它一次性读取多个元素,并将其存储在内存中。
size_t fread(void ptr, size_t size, size_t count, FILE stream);
1
ptr: 指向内存缓冲区的指针,用于存储读取的数据。
size: 每个元素的大小(以字节为单位)。
count: 要读取的元素数量。
stream: 文件指针。
示例:
char data[20];
size_t bytesRead = fread(data, sizeof(char), 20, fp);
if (bytesRead < 20)
{
if (feof(fp))
{
printf("已到达文件末尾。\n");
}
else if (ferror(fp))
{
printf("在到达文件末尾之前发生错误。\n");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
上述代码从文件中读取20个字节的数据到 data 数组中。之后会检查是否达到文件末尾或读取过程中是否出现错误。
2.4 检查文件结束 (feof)
feof 函数用于检查是否到达了文件的末尾。
int feof(FILE *stream);
1
stream: 文件指针。
返回值为非零值表示文件已到达末尾。
- 文件的写入
与读取类似,写入文件也有多种方式,根据数据的格式选择合适的方法。
3.1 使用 fprintf 写入格式化数据
fprintf 用于将格式化数据写入文件,类似于 printf,但它输出到文件而不是标准输出。
int fprintf(FILE stream, const char format, ...);
1
stream: 文件指针。
format: 格式字符串,类似 printf 的格式控制。
示例:
int age = 30;
double salary = 50000.75;
fprintf(fp, "Age: %d, Salary: %.2f\n", age, salary);
1
2
3
该代码将 age 和 salary 以格式化的方式写入文件。
3.2 使用 fputs 写入字符串
fputs 函数将字符串写入文件,不包含终止符 \0。
int fputs(const char str, FILE stream);
1
str: 要写入的字符串。
stream: 文件指针。
示例:
fputs("Hello, World!\n", fp);
1
该代码将 “Hello, World!” 写入文件。
3.3 使用 fwrite 写入二进制数据
fwrite 函数用于将二进制数据写入文件。
size_t fwrite(const void ptr, size_t size, size_t count, FILE stream);
1
ptr: 指向要写入的内存区域。
size: 每个元素的大小(以字节为单位)。
count: 要写入的元素数量。
stream: 文件指针。
示例:
char data[20] = "example data";
fwrite(data, sizeof(char), strlen(data), fp);
1
2
该代码将字符串 “example data” 写入文件(不包括终止符 \0)。
- 关闭文件 (fclose)
文件操作完成后,必须使用 fclose 关闭文件,以确保数据正确写入并释放资源。
int fclose(FILE *stream);
1
stream: 文件指针。
示例:
fclose(fp);
1
该代码关闭之前打开的文件。
- 错误处理
文件操作过程中可能会遇到各种错误,常见的错误处理方式包括检查 fopen、fread、fwrite、fprintf 等函数的返回值。
5.1 fopen 错误处理
fopen 如果无法打开文件,返回 NULL。 可以使用 perror 打印错误原因。
FILE* fp = fopen("example.txt", "r");
if (fp == NULL)
{
perror("打开文件错误");
return -1;
}
1
2
3
4
5
6
5.2 fread 和 fwrite 错误处理
检查 fread 和 fwrite 的返回值以确认是否读取/写入了预期数量的数据。
size_t bytesRead = fread(buffer, sizeof(char), size, fp);
if (bytesRead < size)
{
if (feof(fp))
{
printf("已到文件末尾\n");
}
else if (ferror(fp))
{
perror("读取文件错误\n");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
- 文件指针操作 (fseek, ftell, rewind)
文件指针表示当前文件中的读写位置,通过操作文件指针可以定位到文件的任意位置。
6.1 fseek 函数
fseek 用于移动文件指针到指定的位置。
int fseek(FILE *stream, long int offset, int origin);
1
offset: 偏移量,以字节为单位。
origin: 起始位置:
SEEK_SET: 从文件开头算起。
SEEK_CUR: 从当前指针位置算起。
SEEK_END: 从文件末尾算起。
示例:
fseek(fp, 0, SEEK_SET); // 移动到文件开头
fseek(fp, 0, SEEK_END); // 移动到文件末尾
fseek(fp, 10, SEEK_CUR); // 从当前位置前移10字节
1
2
3
6.2 ftell 函数
ftell 返回当前文件指针的位置(相对于文件开头的字节偏移量)。
long int ftell(FILE *stream);
1
示例:
long int position = ftell(fp);
printf("当前位置: %ld\n", position);
1
2
6.3 rewind 函数
rewind 将文件指针重置到文件开头,功能类似 fseek(fp, 0, SEEK_SET),但 rewind 还会清除文件的错误标志(如果有的话)。
void rewind(FILE *stream);
1
示例:
rewind(fp); // 重置文件指针到文件开头
1
- 文件缓冲区管理 (fflush)
fflush 函数用于刷新文件流的输出缓冲区,确保所有缓冲区的数据都写入到文件中。
int fflush(FILE *stream);
1
stream: 文件指针。如果 stream 为 NULL,则刷新所有打开的输出流。
示例:
fflush(fp);
1
fflush 通常用于在程序结束前或希望立即写入数据时,确保所有数据都写入文件。
- 文件状态和错误检查 (ferror, clearerr)
8.1 ferror 函数
ferror 用于检查文件流是否发生了错误。
int ferror(FILE *stream);
1
stream: 文件指针。
如果发生错误,返回一个非零值。
示例:
if (ferror(fp))
{
printf("文件出现错误\n");
}
1
2
3
4
8.2 clearerr 函数
clearerr 用于清除文件流中的错误和 EOF 状态。
void clearerr(FILE *stream);
1
示例:
clearerr(fp);
1
clearerr 通常在处理错误后调用,以便重新尝试文件操作。