C语言:文件操作
C语言的文件操作是通过标准库提供的函数来实现的,这些函数可以处理文件的读写、定位等操作。文件操作对于开发数据持久化、处理输入输出(I/O)等功能是非常重要的。
3.1 文件打开、关闭与读写
在C语言中,文件操作主要依赖于标准库 <stdio.h>
中的函数,尤其是 fopen
、fclose
、fread
和 fwrite
等。
-
fopen:用于打开文件。它会返回一个文件指针,之后我们通过该指针对文件进行读写操作。
语法:
FILE *fopen(const char *filename, const char *mode);
filename
:要打开的文件名(包括路径)。mode
:文件的打开模式。常见模式有:"r"
:只读模式,文件必须存在。"w"
:写模式,若文件不存在则创建,若存在则清空文件内容。"a"
:追加模式,文件若不存在则创建,若存在则从文件末尾开始写入。"rb"
:以二进制模式只读打开文件。"wb"
:以二进制模式写入文件。"r+"
:以读写模式打开文件。
示例代码:
FILE *file = fopen("example.txt", "w"); if (file == NULL) { printf("无法打开文件。\n"); } else { fprintf(file, "Hello, C Programming!\n"); fclose(file); }
-
fclose:用于关闭文件,释放文件指针资源。
语法:
int fclose(FILE *stream);
示例代码:
FILE *file = fopen("example.txt", "r"); if (file != NULL) { // 文件操作 fclose(file); }
-
FILE*:文件指针
- 定义:
FILE *
是 C 标准库中定义的一个结构体指针,专门用于文件操作。该结构体由操作系统管理,程序员通过该指针来操作文件。不同的系统可能略有差异,但是类型名FILE是一样的。
typedef struct { int handle; // 文件描述符(操作系统级别的文件句柄) unsigned char *buf; // 文件的缓冲区 size_t buf_size; // 缓冲区的大小 size_t buf_pos; // 当前缓冲区的位置 int flags; // 文件标志,如读、写等 long offset; // 文件的当前偏移量 } FILE;
- 作用:
FILE *
允许程序对文件进行操作,如打开、关闭、读取、写入、定位指针等。
- 定义:
-
fread:从文件中读取数据。
语法:
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
ptr
:指向存储读取数据的缓冲区。size
:每个数据项的大小(字节数)。count
:要读取的数据项个数。stream
:文件指针。
示例代码:
FILE *file = fopen("example.txt", "r"); if (file != NULL) { char buffer[100]; size_t bytesRead = fread(buffer, sizeof(char), 100, file); buffer[bytesRead] = '\0'; // 确保字符串结束符 printf("读取的数据: %s\n", buffer); fclose(file); }
-
fwrite:向文件中写入数据。
语法:
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
ptr
:指向要写入数据的内存位置。size
:每个数据项的大小(字节数)。count
:要写入的数据项个数。stream
:文件指针。
示例代码:
FILE *file = fopen("example.bin", "wb"); if (file != NULL) { int numbers[] = {1, 2, 3, 4}; fwrite(numbers, sizeof(int), 4, file); fclose(file); }
-
fprintf:格式化输出到文件。
- 语法:
int fprintf(FILE *stream, const char *format, ...);
- 示例:将数据写入文本文件
FILE *file = fopen("example.txt", "w"); if (file != NULL) { int a = 5; float b = 3.14; fprintf(file, "整数: %d, 浮点数: %.2f\n", a, b); fclose(file); }
-
fscanf:从文件中格式化输入。
- 语法:
int fscanf(FILE *stream, const char *format, ...);
- 示例:从文件中读取数据
FILE *file = fopen("example.txt", "r"); if (file != NULL) { int a; float b; fscanf(file, "整数: %d, 浮点数: %f", &a, &b); printf("读取到数据: %d, %.2f\n", a, b); fclose(file); }
-
fputc:写入一个字符到文件。
- 语法:
int fputc(int c, FILE *stream);
- 示例:写入单个字符
FILE *file = fopen("example.txt", "w"); if (file != NULL) { fputc('A', file); // 写入字符 'A' fclose(file); }
-
fgetc:从文件中读取一个字符。
- 语法:
int fgetc(FILE *stream);
- 示例:逐字符读取文件
FILE *file = fopen("example.txt", "r"); if (file != NULL) { int ch = fgetc(file); printf("读取的字符: %c\n", ch); fclose(file); }
3.2 文本文件与二进制文件的操作
C语言可以处理文本文件和二进制文件,它们的区别在于数据存储和处理方式。
- 文本文件:文件内容以字符形式存储,每个字符占用一个字节,数据存储通常为人可读的格式。
- 通过
fopen
以文本模式打开(如"r"
、"w"
等)。 - 读取操作通常是以行或字符的形式进行。
- 通过
- 二进制文件:文件内容存储为原始二进制数据,通常不容易直接由人阅读。
- 通过
fopen
以二进制模式打开(如"rb"
、"wb"
等)。 - 读取操作通常是以二进制块的形式进行,常用于存储结构化数据(如图像、音频、数据库文件等)。
- 通过
文本文件操作示例:
FILE *file = fopen("textfile.txt", "w");
if (file != NULL) {
fprintf(file, "This is a text file.\n");
fclose(file);
}
二进制文件操作示例:
FILE *file = fopen("binaryfile.bin", "wb");
if (file != NULL) {
int data[] = {1, 2, 3, 4};
fwrite(data, sizeof(int), 4, file); // 写入整数数组
fclose(file);
}
3.3 文件指针与文件定位
文件指针用于指示文件中的当前位置,C语言提供了一些函数来获取和设置文件指针的位置。
-
ftell:获取文件指针的当前位置,返回一个
long
类型值,表示文件中的字节数。语法:
long ftell(FILE *stream);
示例代码:
FILE *file = fopen("example.txt", "r"); if (file != NULL) { fseek(file, 0, SEEK_END); // 移动到文件末尾 long position = ftell(file); // 获取文件指针位置 // 获取文件大小 printf("文件大小: %ld bytes\n", position); fclose(file); }
//注: 对于获取文件大小等信息,不一定要打开文件
#include <stdio.h> #include <sys/stat.h> int main() { const char *filename = "example.txt"; // 文件名 struct stat fileStat; // 用来存储文件信息 // 获取文件的状态信息 if (stat(filename, &fileStat) == -1) { perror("stat"); // 打印错误信息 return 1; } // 打印文件大小 printf("File size: %lld bytes\n", (long long)fileStat.st_size); return 0; }
-
fseek:设置文件指针的位置。
语法:
int fseek(FILE *stream, long offset, int whence);
offset
:相对当前位置的偏移量。whence
:指定偏移量的参考位置,常见值有:SEEK_SET
:从文件开头开始偏移。SEEK_CUR
:从当前文件指针位置偏移。SEEK_END
:从文件末尾开始偏移。
示例代码:
FILE *file = fopen("example.txt", "r"); if (file != NULL) { fseek(file, 10, SEEK_SET); // 移动文件指针到文件开头的第10个字节 char ch = fgetc(file); // 读取当前位置的字符 printf("当前位置字符: %c\n", ch); fclose(file); }
-
rewind:将文件指针移到文件开头,相当于
fseek(file, 0, SEEK_SET)
。语法:
void rewind(FILE *stream);
3.4 错误处理:feof、ferror
C语言提供了两种函数来检查文件操作中的错误或是否到达文件末尾:
-
feof:检测文件是否已到达末尾。返回非零值表示文件结束,返回零表示文件未到达末尾。
语法:
int feof(FILE *stream);
示例代码:
FILE *file = fopen("example.txt", "r"); if (file != NULL) { char ch; while ((ch = fgetc(file)) != EOF) { // 读取直到文件末尾 putchar(ch); } if (feof(file)) { printf("\n文件读取结束。\n"); } fclose(file); }
-
ferror:检查文件操作是否出错。返回非零值表示发生错误,返回零表示没有错误。
语法:
int ferror(FILE *stream);
示例代码:
FILE *file = fopen("example.txt", "r"); if (file != NULL) { if (ferror(file)) { printf("文件错误发生!\n"); } fclose(file); }
-
clearerr:清除文件流的错误标志和文件末尾标志。
- 语法:
void clearerr(FILE *stream);
- 示例:清除文件流的错误标志
FILE *file = fopen("example.txt", "r"); if (file != NULL) { // 进行文件读取 if (ferror(file)) { clearerr(file); // 清除错误标志 } fclose(file); }
注意,清除错误标志 并不是清空缓冲区,对于scanf等函数读取错误,需要使用getchar清空缓冲区才有效。
while (getchar() != ‘\n’ && getchar() != EOF);
3.5 文件模式
文件打开时的模式决定了文件的访问权限(只读、只写、追加等)。常见的模式包括:
- r:只读模式,文件必须存在。
- w:写模式,若文件存在则清空文件内容,若文件不存在则创建。
- a:追加
模式,文件若不存在则创建,若存在则从文件末尾开始写入。
- rb:以二进制模式只读打开文件。
- wb:以二进制模式写入文件。
- r+:读写模式,文件必须存在。
- w+:读写模式,文件存在则清空,文件不存在则创建。
- a+:读写模式,文件末尾追加,文件若不存在则创建。
3.6 文件与目录操作
除了标准的文件读写操作外,C语言还支持一些操作文件和目录的函数,常用于文件系统管理。
-
rename:重命名文件。
- 语法:
int rename(const char *oldname, const char *newname);
- 示例:
int result = rename("oldfile.txt", "newfile.txt"); if (result == 0) { printf("文件重命名成功!\n"); } else { printf("文件重命名失败!\n"); }
-
remove:删除文件。
- 语法:
int remove(const char *filename);
- 示例:
int result = remove("example.txt"); if (result == 0) { printf("文件删除成功!\n"); } else { printf("文件删除失败!\n"); }
-
tmpfile:创建一个临时文件并返回文件指针。该文件在程序结束时自动删除。
- 语法:
FILE *tmpfile(void);
- 示例:
FILE *file = tmpfile(); if (file != NULL) { fprintf(file, "临时文件内容\n"); fclose(file); }
3.7 其他文件操作函数
-
setvbuf:设置文件流的缓冲区模式(全缓冲、行缓冲、无缓冲)。
- 语法:
int setvbuf(FILE *stream, char *buffer, int mode, size_t size);
- 示例:
char buf[1024]; FILE *file = fopen("example.txt", "w"); setvbuf(file, buf, _IOFBF, sizeof(buf)); // 设置全缓冲 fprintf(file, "使用缓冲区写入数据。\n"); fclose(file);
-
fflush:刷新文件流的缓冲区,确保所有数据被写入文件。(非标准)
- 语法:
int fflush(FILE *stream);
- 示例:
FILE *file = fopen("example.txt", "w"); fprintf(file, "数据写入文件\n");fflush(file); // 强制刷新缓冲区fclose(file);