文件I/O(输入/输出)是C语言中处理文件读写操作的重要部分。通过文件I/O,可以将数据从程序写入文件或从文件读取数据进入程序。C语言提供了一套标准库函数,用于处理文件的打开、读写、关闭等操作。
文件I/O的基本操作
1.打开文件:使用 fopen() 函数。FILE *fopen(const char *filename, const char *mode);
filename 是要打开的文件的名称,mode 是打开文件的模式,例如读取、写入或追加。返回值:成功返回建立的文件流指针,失败返回NULL
常见模式:
"r":以只读方式打开文件,文件必须存在。
"w":以写入方式打开文件,文件不存在时创建,存在时清空内容。
"a":以追加方式打开文件,文件不存在时创建,存在时在末尾添加内容。
"r+":以读写方式打开文件,文件必须存在。
"w+":以读写方式打开文件,文件不存在时创建,存在时清空内容。
"a+":以读写方式打开文件,文件不存在时创建,存在时在末尾添加内容。
2.读写操作:
- 写入文件:使用 fprintf()、fputs()、fputc() 等函数。
- fputc(int char, FILE *stream):将字符写入文件。
- fputs(const char *str, FILE *stream):将字符串写入文件。
- fprintf(FILE *stream, const char *format, ...):格式化写入数据到文件。
- 读取文件:使用 fscanf()、fgets()、fgetc() 等函数。
- fgets(char *str, int n, FILE *stream):从文件读取一行字符。
- fscanf(FILE *stream, const char *format, ...):格式化从文件读取数据。
- fgetc(FILE *stream):从文件读取一个字符
3.关闭文件:使用 fclose() 函数。int fclose(FILE *stream);
关闭文件,释放与文件关联的资源。stream要关闭的文件流的指针。
4.文件定位:
1.设置文件位置:使用 fseek() 函数。 int fseek(FILE *stream, long offset, int whence);
whence 可以是 SEEK_SET(从文件头开始),SEEK_CUR(从当前位置开始),SEEK_END(从文件末尾开始)。
2.获取文件位置:使用 ftell() 函数。long ftell(FILE *stream);
返回文件位置指针相对于文件开头的偏移量。
5.错误处理:
检测错误:使用 ferror() 函数。 int ferror(FILE *stream);
如果发生错误,返回非零值。
清除错误标志:使用 clearerr() 函数。void clearerr(FILE *stream);
接下来重点说下输入输出函数
1. fgetc() 函数 int fgetc(FILE *stream);
stream:指向文件的指针,表示要读取的文件。成功时返回读取的字符(以 int类型返回),如果到达文件末尾(EOF),或者发生读取错误,则返回 `EOF。常用于逐个字符处理文件内容,如统计字符、逐字分析等。
功能:fgetc() 用于从文件中读取一个字符,每次调用返回下一个字符。读取的字符包括文件中的换行符和空白字符。
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "r");//打开文件
if (file == NULL) {
printf("无法打开文件\n");
return 1;
}
int ch;
while ((ch = fgetc(file)) != EOF) {
putchar(ch); // 输出读取的字符
}
fclose(file);//关闭文件
return 0;
}
2. fputc()函数 int fputc(int char, FILE *stream);
char:要写入的字符(以 int类型表示)。
stream:指向文件的指针,表示要写入的文件。
功能: fputc()用于向文件中写入一个字符。成功时返回写入的字符。如果发生错误,返回 EOF。常用于逐个字符写入文件,如生成字符流或构建特殊格式的输出。
#include <stdio.h>
int main() {
FILE *file = fopen("output.txt", "w");
if (file == NULL) {
printf("无法打开文件\n");
return 1;
}
fputc('A', file); // 写入字符 'A'
fputc('B', file); // 写入字符 'B'
fclose(file);
return 0;
}
3. fgets()函数 char *fgets(char *str, int n, FILE *stream);
str:用于存储读取的字符串的字符数组。
n:指定最多读取的字符数,包括最后的空字符 `\0`。
stream:指向文件的指针,表示要读取的文件。
功能:fgets()用于从文件中读取一行字符串,并将其存储在指定的字符数组中。它会读取直到遇到换行符、到达指定的最大长度,或者遇到文件结尾(EOF)为止。成功时返回指向读取字符串的指针,即 str。如果到达文件末尾且没有读取到任何数据,或发生读取错误,则返回 NULL。常用于读取行文本,如处理配置文件、逐行处理文本文件等。
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "r");
if (file == NULL) {
printf("无法打开文件\n");
return 1;
}
char buffer[100];
while (fgets(buffer, 100, file) != NULL) {
printf("%s", buffer); // 输出读取的字符串
}
fclose(file);
return 0;
}
4.fputs() 函数 int fputs(const char *str, FILE *stream);
str:要写入的字符串。
stream:指向文件的指针,表示要写入的文件。
功能:fputs()用于向文件中写入一个字符串。成功时返回一个非负数。如果发生错误,返回EOF。常用于写入整行或多行文本,如写入日志、输出常规文本等。
#include <stdio.h>
int main() {
FILE *file = fopen("output.txt", "w");
if (file == NULL) {
printf("无法打开文件\n");
return 1;
}
fputs("Hello, World!\n", file); // 写入字符串 "Hello, World!"
fclose(file);
return 0;
}
5.fread()和 fwrite()是C语言中处理二进制数据的标准库函数,通常用于从文件中读取或向文件中写入块状数据。这两个函数比 fgetc()和 fputc() 更高效,因为它们可以一次性处理多个字节的数据。它们能高效地读取和写入数据块,非常适合处理包含任意字节数据的文件,如图片和音频文件。
fread()函数 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
ptr:指向接收读取数据的内存缓冲区的指针。
size:每个数据块的大小(以字节为单位)。
nmemb:要读取的块的数量。
stream:指向文件的指针,表示要读取的文件。
功能:fread()用于从文件中读取指定数量的数据块,并将其存储到内存中的缓冲区中。 成功时返回实际读取的块数(通常等于 nmemb,除非遇到文件末尾或读取错误).如果遇到文件末尾或发生错误,返回的块数可能小于 nmemb.
fwrite()函数 size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
ptr:指向要写入数据的内存缓冲区的指针。
size:每个数据块的大小(以字节为单位)。
nmemb:要写入的块的数量。
stream:指向文件的指针,表示要写入的文件。
功能fwrite()用于将指定数量的数据块从内存中的缓冲区写入文件中。 成功时返回实际写入的块数(通常等于 nmemb,除非发生写入错误)。-如果发生写入错误,返回的块数可能小于 nmemb。
#include <stdio.h>
int main() {
FILE *srcFile, *destFile;
char buffer[1024]; // 定义一个缓冲区
size_t bytesRead;
// 以二进制读模式打开源文件
srcFile = fopen("source.jpg", "rb");
if (srcFile == NULL) {
printf("无法打开源文件\n");
return 1;
}
// 以二进制写模式打开目标文件
destFile = fopen("copy.jpg", "wb");
if (destFile == NULL) {
printf("无法创建目标文件\n");
fclose(srcFile);
return 1;
}
// 逐块读取并写入
while ((bytesRead = fread(buffer, 1, sizeof(buffer), srcFile)) > 0) {
fwrite(buffer, 1, bytesRead, destFile);
}
// 关闭文件
fclose(srcFile);
fclose(destFile);
printf("文件复制完成\n");
return 0;
}
注意:
fgets() 和 fputs() 是用于处理文本数据的函数,专门用来读取和写入字符串(文本行)。它们处理数据时有一些特性使它们不适合处理二进制数据(如图片、音频、视频等)。fputc()与fputc()
fread()与fwrite()可以处理图片。
1. 文本 vs. 二进制数据
文本数据:由可打印的字符组成(如字母、数字、标点符号等),以字符串形式存储,通常以换行符结束。
二进制数据:可以包含任何字节值,包括不可打印字符和控制字符,这些数据不能直接用字符串处理函数进行操作。
2. fgets() 的限制
fgets() 是为读取文本行设计的,它会在遇到换行符 \n、文件结尾 EOF 或达到最大字符数时停止。
读取的字符串会自动添加一个空字符 \0 来表示字符串结束。这种处理方式对二进制文件不适用,因为二进制文件的数据并不一定是以可打印字符形式组织的,可能包含任意字节值。
3. fputs() 的限制
fputs() 是为写入字符串设计的,它要求输入是一个以空字符 \0 结束的字符串。它会继续写入数据直到遇到 \0。
如果你使用 fputs() 来写入二进制数据,任何遇到的空字符都会被认为是字符串的结尾,导致数据写入不完整。