目录
1 文件的存储形式
2 打开文件——fopen() 函数
2.1 功能描述
2.2 函数原型
2.3 文件打开方式(模式)
3 关闭文件——fclose() 函数
3.1 功能描述
3.2 函数原型
4 常见的文件写入方式
4.1 fputc() 函数
4.1.1 功能描述
4.1.2 函数原型
4.1.3 案例演示
4.2 fputs() 函数
4.2.1 功能说明
4.2.2 函数原型
4.2.3 案例演示
4.3 fprintf() 函数
4.3.1 功能说明
4.3.2 函数原型
4.3.3 案例演示
4.4 文件写入——综合案例演示
5 常见的文件写入方式
5.1 fgetc() 函数
5.1.1 功能说明
5.1.2 函数原型
5.1.3 案例演示
5.2 fgets() 函数
5.2.1 功能说明
5.2.2 函数原型
5.2.3 案例演示
5.3 fscanf 函数
5.2.1 功能说明
5.2.2 函数原型
5.2.3 案例演示
1 文件的存储形式
文件,无论是文本文件还是二进制文件,都是以连续的字节序列形式存储在存储设备上的。这种存储方式确保了文件内容的完整性和可访问性,同时也为高效的文件管理和操作提供了基础。C 语言为此提供了一套全面且强大的函数库,使得开发者能够方便地进行文件的读取、写入、更新等操作。
- 文本文件:通常由人类可读的字符组成,每个字符占用一个字节(在 ASCII 编码中)或多个字节(在 Unicode 编码中)。文本文件通常用于存储源代码、配置信息、日志记录等。在不同的操作系统中,文本文件的换行符可能有所不同(例如,Windows 使用 \r\n,而 Unix/Linux 使用 \n)。
- 二进制文件:可以包含任何类型的字节序列,包括非打印字符。二进制文件通常用于存储图像、音频、视频等多媒体数据,以及编译后的程序代码。由于二进制文件的内容不是人类直接可读的,因此在读写时需要特别注意数据的格式和结构。
2 打开文件——fopen() 函数
2.1 功能描述
fopen() 函数主要用于打开一个文件,或者创建一个新文件。它允许程序以读取、写入或追加的方式访问文件。如果指定的文件不存在,某些模式下 fopen() 可能会创建该文件。如果文件存在,某些模式可能会清除文件内容或在文件末尾追加内容。
2.2 函数原型
#include <stdio.h>
FILE *fopen(const char *filename, const char *mode);
参数:
- filename:一个指向以 null 结尾的字符串的指针,该字符串包含了要打开的文件的路径(位置 + 名称),路径可以是绝对路径,也可以是相对路径。
- 绝对路径:从根目录开始的完整路径。在 Unix/Linux 系统中使用正斜杠
/
,在 Windows 系统中可以使用反斜杠\
,但需要注意使用转义字符\\
,或者使用正斜杠/
也是兼容的。 - 相对路径:相对于当前工作目录的路径。
- 绝对路径:从根目录开始的完整路径。在 Unix/Linux 系统中使用正斜杠
- mode:一个指向以 null 结尾的字符串的指针,该字符串指定了打开文件的方式。详情见表2.3。
返回值:
- 成功时返回一个指向 FILE 类型的指针,表示已打开的文件流。
- 失败时返回 NULL。
2.3 文件打开方式(模式)
模式 | 描述 |
---|---|
r | 只读模式。 打开一个已存在的文本文件,只允许读取文件。如果文件不存在,则打开失败。 |
w | 只写模式。 打开一个文本文件,从头写入文件。如果文件不存在,则会创建一个新文件并写入;如果文件存在,则清空文件并从头写入。 |
a | 追加模式。 打开一个文本文件,追加写入文件。如果文件不存在,则会创建一个新文件并写入;如果文件存在,在已有内容后面追加写入。 |
rb | 只读二进制模式。 打开一个已存在的二进制文件,只允许读取文件。如果文件不存在,则打开失败。 |
wb | 只写二进制模式。 打开一个二进制文件,从头写入文件。如果文件不存在,则会创建一个新文件并写入;如果文件存在,则清空文件并从头写入。 |
ab | 追加二进制模式。 打开一个二进制文件,追加写入文件。如果文件不存在,则会创建一个新文件并写入;如果文件存在,在已有内容后面追加写入。 |
r+ | 读写模式。 打开一个已存在的文本文件,允许读写文件。文件指针位于文件开头。如果文件不存在,则打开失败。 |
w+ | 读写模式。 打开一个文本文件,从头读写文件。如果文件不存在,则会创建一个新文件并读写;如果文件存在,则清空文件并从头读写。 |
a+ | 读写模式。 打开一个文本文件,读取或追加写入文件。如果文件不存在,则会创建一个新文件并读写;如果文件存在,文件指针位于文件末尾,读取时从开头开始,写入时在已有内容后面追加。 |
rb+ | 读写二进制模式。 打开一个已存在的二进制文件,允许读写文件。文件指针位于文件开头。如果文件不存在,则打开失败。 |
r+b | 读写二进制模式。 同 |
wb+ | 读写二进制模式。 打开一个二进制文件,从头读写文件。如果文件不存在,则会创建一个新文件并读写;如果文件存在,则清空文件并从头读写。 |
w+b | 读写二进制模式。 同 |
ab+ | 读写二进制模式。 打开一个二进制文件,读取或追加写入文件。如果文件不存在,则会创建一个新文件并读写;如果文件存在,文件指针位于文件末尾,读取时从开头开始,写入时在已有内容后面追加。 |
a+b | 读写二进制模式。 同 |
补充说明:
- 文件指针位置:在某些模式下,文件指针的位置是固定的。例如,在
a
和a+
模式下,文件指针默认位于文件末尾,但在读取时可以从文件开头开始。 - 文件创建:在
w
、a
、w+
、a+
、wb
、ab
、wb+
、ab+
模式下,如果文件不存在,fopen()
会创建一个新文件。 - 文件清空:在
w
、w+
、wb
、wb+
模式下,如果文件已经存在,fopen()
会清空文件内容。 - 文本与二进制模式:文本模式(
r
、w
、a
、r+
、w+
、a+
)在某些系统上会对换行符进行转换,而二进制模式(rb
、wb
、ab
、rb+
、wb+
、ab+
)则不会进行任何转换。 - 不会创建目录:无论使用哪种模式,fopen 函数都不会创建目录。fopen 只负责打开或创建文件,但不会创建文件路径中不存在的目录。如果指定的路径中的某个目录不存在,fopen 会失败并返回 NULL。
- 读文件:从文件中读取数据到内存中,对于内存来说是输入流。
- 写文件:将内存中的数据写入到文件中,对于内存来说是输出流。
3 关闭文件——fclose() 函数
3.1 功能描述
fclose() 函数的主要功能是关闭一个文件流。当文件流被关闭时,所有未写入磁盘的缓冲区数据会被刷新,文件指针和相关资源会被释放。关闭文件是一个重要的步骤,可以避免资源泄漏和数据丢失。
3.2 函数原型
#include <stdio.h>
int fclose(FILE *stream);
参数:
- stream:一个指向 FILE 类型的指针,表示要关闭的文件流。这个指针通常是通过 fopen() 函数获得的。
返回值:
- 如果文件成功关闭,返回 0。
- 如果关闭文件时发生错误,返回 EOF(通常定义为 -1)。
4 常见的文件写入方式
4.1 fputc() 函数
4.1.1 功能描述
fputc() 函数的主要功能是将一个字符写入指定的文件流中。如果写入成功,该函数返回写入的字符;如果写入失败,返回 EOF。
4.1.2 函数原型
#include <stdio.h>
int fputc(int c, FILE *stream);
参数:
- c:要写入的字符。虽然参数类型是 int,但实际上传递的是一个字符(char 类型),因为 EOF 也是一个 int 类型的特殊值。
- stream:一个指向 FILE 类型的指针,表示要写入的文件流。这个指针通常是通过 fopen() 函数获得的。
返回值:
- 如果字符成功写入文件,返回写入的字符(转换为 unsigned char 后再转换为 int)。
- 如果写入失败,返回 EOF(通常定义为 -1)。
4.1.3 案例演示
#include <stdio.h>
int main()
{
// 打开文件,使用追加模式('a')。如果文件不存在,则会创建一个新文件
// 如果文件存在,则会在文件末尾追加内容
// 如果指定的路径中的某个目录不存在,fopen 会失败,并返回 NULL
FILE *file = fopen("./path/files/output1.txt", "a"); // 追加写入
// 检查文件是否成功打开
if (file != NULL)
{
// 定义要写入的字符
char ch = 'A';
// 使用 fputc 函数写入一个字符
int result1 = fputc(ch, file);
// 检查 fputc 是否成功
if (result1 != EOF)
{
// 如果写入成功,输出成功信息及返回值
printf("成功使用 fputc 写入字符 '%c',返回值:%d。\n", ch, result1);
}
else
{
// 如果写入失败,输出错误信息
printf("使用 fputc 写入字符时出现错误。\n");
}
// 关闭文件
fclose(file);
}
else
{
// 如果文件打开失败,输出错误信息
printf("打开文件时出现错误。\n");
}
return 0;
}
输出结果如下所示:
4.2 fputs() 函数
4.2.1 功能说明
fputs() 函数的主要功能是将一个字符串(不包括终止的空字符 '\0')写入指定的文件流中,如果字符串中包含换行符 '\n',fputs 会将其原样写入文件。如果写入成功,该函数返回一个非负值;如果写入失败,返回 EOF。
4.2.2 函数原型
#include <stdio.h>
int fputs(const char *str, FILE *stream);
参数:
- str:一个指向以 null 结尾的字符串的指针,表示要写入的字符串。
- stream:一个指向 FILE 类型的指针,表示要写入的文件流。这个指针通常是通过 fopen() 函数获得的。
返回值:
- 如果字符串成功写入文件,返回一个非负值(通常是成功写入的字符数,具体取决于编译器)。
- 如果写入失败,返回 EOF(通常定义为 -1)。
4.2.3 案例演示
#include <stdio.h>
int main()
{
// 打开文件,使用写入模式('w')。如果文件存在,则清空文件;如果文件不存在,则创建新文件
FILE *file = fopen("./path/files/output2.txt", "w"); // 从头写入
if (file != NULL)
{
// 定义要写入的字符串
const char *text = "使用写入模式('w')。如果文件存在,则清空文件;如果文件不存在,则创建新文件\n";
// 使用 fputs 函数写入字符串
int result = fputs(text, file);
// 检查 fputs 是否成功
if (result != EOF)
{
// 如果写入成功,输出成功信息及返回值
printf("成功使用 fputs 写入字符串,返回值:%d。\n", result);
}
else
{
// 如果写入失败,输出错误信息
printf("使用 fputs 写入字符串时出现错误。\n");
}
// 关闭文件
fclose(file);
}
else
{
// 如果文件打开失败,输出错误信息
printf("打开文件时出现错误。\n");
}
return 0;
}
输出结果如下所示:
4.3 fprintf() 函数
4.3.1 功能说明
fprintf() 函数的主要功能是将格式化的字符串写入指定的文件流中,如果格式化字符串中包含换行符 '\n',fprintf 会将其原样写入文件。它可以接受多个参数,并根据提供的格式字符串将这些参数格式化后写入文件。如果写入成功,该函数返回写入的字符数;如果写入失败,返回一个负值。
4.3.2 函数原型
#include <stdio.h>
int fprintf(FILE *stream, const char *format, ...);
参数:
- stream:一个指向 FILE 类型的指针,表示要写入的文件流。这个指针通常是通过 fopen() 函数获得的。
- format:一个指向以 null 结尾的字符串的指针,表示格式化字符串。格式化字符串可以包含普通字符和格式化说明符(如 %d、%s、%f 等),与 printf 类似。
- ...:可变参数列表,根据格式化字符串中的说明符提供相应的参数,与 printf 类似。
返回值:
- 如果写入成功,返回写入的字符数(不包括终止符 '\0')。
- 如果写入失败,返回一个负值。
4.3.3 案例演示
#include <stdio.h>
int main()
{
// 打开文件,使用写入模式('w')。如果文件存在,则清空文件;如果文件不存在,则创建新文件
FILE *file = fopen("./path/files/output3.txt", "w"); // 从头写入
if (file != NULL)
{
// 定义要写入的格式化字符串
const char *text = "fprintf: %s is studying in CSDN_Thanks_ks\n";
char *name = "Alice";
// 使用 fprintf 函数写入格式化的字符串
int result = fprintf(file, text, name);
// 检查 fprintf 是否成功
if (result != EOF)
{
// 如果写入成功,输出成功信息及返回值
printf("成功使用 fprintf 写入字符串,返回值:%d。\n", result);
}
else
{
// 如果写入失败,输出错误信息
printf("使用 fprintf 写入字符串时出现错误。\n");
}
// 关闭文件
fclose(file);
}
else
{
// 如果文件打开失败,输出错误信息
printf("打开文件时出现错误。\n");
}
return 0;
}
输出结果如下所示:
4.4 文件写入——综合案例演示
#include <stdio.h>
int main()
{
// 以追加模式('a')打开文件。如果文件不存在,则会创建一个新文件
// 如果文件存在,则会在文件末尾追加内容
FILE *file = fopen("./path/files/output4.txt", "a"); // 追加写入
if (file != NULL)
{
// 使用 fputc 写入一个字符
char ch = 'A';
int result1 = fputc(ch, file);
if (result1 != EOF)
{
// 如果 fputc 成功,输出成功信息及返回值
printf("成功使用 fputc 写入字符 '%c',返回值:%d。\n", ch, result1);
}
else
{
// 如果 fputc 失败,输出错误信息
printf("使用 fputc 写入字符时出现错误。\n");
}
// 使用 fputs 写入一个字符串
const char *text = "fputs: Welcome to my blog, I am Thanks_ks\n";
int result2 = fputs(text, file);
if (result2 != EOF)
{
// 如果 fputs 成功,输出成功信息及返回值
printf("成功使用 fputs 写入字符串,返回值:%d。\n", result2);
}
else
{
// 如果 fputs 失败,输出错误信息
printf("使用 fputs 写入字符串时出现错误。\n");
}
// 使用 fprintf 写入格式化数据
int num = 42;
float pi = 3.14159;
const char *formattedText = "fprintf: %d %.2f\n";
int result3 = fprintf(file, formattedText, num, pi);
if (result3 >= 0)
{
// 如果 fprintf 成功,输出成功信息及返回值
printf("成功使用 fprintf 写入格式化数据,返回值:%d。\n", result3);
}
else
{
// 如果 fprintf 失败,输出错误信息
printf("使用 fprintf 写入格式化数据时出现错误。\n");
}
// 关闭文件,释放与文件相关的资源
fclose(file);
}
else
{
// 如果文件打开失败,输出错误信息
printf("打开文件时出现错误。\n");
}
return 0;
}
输出结果如下所示:
5 常见的文件写入方式
5.1 fgetc() 函数
5.1.1 功能说明
fgetc() 函数的主要功能是从指定的文件流中读取一个字符。如果读取成功,该函数返回读取到的字符;如果到达文件末尾或发生错误,返回 EOF。
5.1.2 函数原型
#include <stdio.h>
int fgetc(FILE *stream);
参数:
- stream:一个指向 FILE 类型的指针,表示要读取的文件流。这个指针通常是通过 fopen() 函数获得的。
返回值:
- 如果读取成功,返回读取到的字符(以 int 类型返回,以便区分 EOF)。
- 如果到达文件末尾或发生错误,返回 EOF(通常定义为 -1)。
5.1.3 案例演示
#include <stdio.h>
int main()
{
// 以读取模式('r')打开文件 "intput.txt"
FILE *file = fopen("./path/files/input1.txt", "r"); // 打开文件以供读取
if (file != NULL)
{
int ch; // 用于存储读取的字符
puts("使用 fgetc 循环读取的文件内容:"); // puts 自带换行效果
// 使用 fgetc 逐字符读取文件
while ((ch = fgetc(file)) != EOF)
{
// printf("%c", ch); // 将字符显示在屏幕上
putchar(ch);
}
fclose(file); // 关闭文件
}
else
{
printf("Error opening the file.\n"); // 如果文件打开失败,输出错误信息
}
return 0;
}
input1.txt 内容如下所示:
输出结果如下所示:
5.2 fgets() 函数
5.2.1 功能说明
fgets() 函数的主要功能是从指定的文件流中读取一行文本,并将其存储到指定的缓冲区中。如果读取成功,该函数返回指向缓冲区的指针;如果到达文件末尾或发生错误,返回 NULL。
5.2.2 函数原型
#include <stdio.h>
char *fgets(char *str, int n, FILE *stream);
参数:
- str:一个指向字符数组的指针,表示用于存储读取到的字符串的缓冲区。
- n:一个整数,表示缓冲区的最大长度。fgets 最多读取 n-1 个字符,并在末尾添加一个空字符 '\0'。
- stream:一个指向 FILE 类型的指针,表示要读取的文件流。这个指针通常是通过 fopen() 函数获得的。
返回值:
- 如果读取成功,返回指向缓冲区的指针(即 str)。
- 如果到达文件末尾或发生错误,返回 NULL。
5.2.3 案例演示
#include <stdio.h>
int main()
{
// 以读取模式('r')打开文件 "intput.txt"
FILE *file = fopen("./path/files/input2.txt", "r"); // 打开文件以供读取
if (file != NULL)
{
char buffer[1000]; // 用于存储读取的字符串
// 使用 fgets 逐行读取文件
while (fgets(buffer, sizeof(buffer), file) != NULL)
{
// printf("%s", buffer); // 将读取的字符串显示在屏幕上
puts(buffer);
}
fclose(file); // 关闭文件
}
else
{
printf("Error opening the file.\n"); // 如果文件打开失败,输出错误信息
}
return 0;
}
input2.txt 内容如下所示:
输出结果如下所示:
5.3 fscanf 函数
5.2.1 功能说明
fscanf() 函数的主要功能是从指定的文件流中读取格式化的输入,并将数据存储到指定的变量中。它类似于 scanf() 函数,但作用于文件流而不是标准输入。fscanf() 使用空白字符(空格、制表符、换行符等)分隔内容,并将其赋值给不同的变量。
5.2.2 函数原型
#include <stdio.h>
int fscanf(FILE *stream, const char *format, ...);
参数:
- stream:一个指向 FILE 类型的指针,表示要读取的文件流。这个指针通常是通过 fopen() 函数获得的。
- format:一个指向以 null 结尾的字符串的指针,表示在··在·格式化字符串。格式化字符串可以包含普通字符和格式化说明符(如 %d、%s、%f 等),与 scanf 类似。
- ...:可变参数列表,根据格式化字符串中的说明符提供相应的指针,与 scanf 类似。
返回值:
- 如果读取成功,返回成功读取并赋值的项数。
- 如果到达文件末尾或发生错误,返回 EOF。
5.2.3 案例演示
#include <stdio.h>
int main()
{
// 以读取模式('r')打开文件 "input3.txt"
FILE *file = fopen("./path/files/input3.txt", "r"); // 打开文件以供读取
if (file != NULL)
{
// 定义变量用于存储读取的数据
char msg1[100], msg2[100], msg3[100]; // 用于存储三个字符串
int num; // 用于存储一个整数
// 使用 fscanf 从文件中读取格式化的数据
fscanf(file, "%s %s %s %d", msg1, msg2, msg3, &num);
// 将读取的数据输出到控制台
printf("%s\n", msg1); // 输出第一个字符串
printf("%s\n", msg2); // 输出第二个字符串
printf("%s\n", msg3); // 输出第三个字符串
printf("%d\n", num); // 输出整数
// 关闭文件
fclose(file);
}
else
{
// 如果文件打开失败,输出错误信息
printf("打开文件时出现错误。\n");
}
return 0;
}
input3.txt 内容如下所示:
输出结果如下所示: