Appearance
文件操作
概述
文件操作是C语言中重要的输入输出功能,通过标准库提供的函数,可以方便地进行文件的读取、写入和管理。
文件指针
FILE类型是C标准库定义的结构体,用于表示文件流。
c
FILE *fp;文件的打开与关闭
fopen函数
c
FILE *fopen(const char *filename, const char *mode);打开模式:
| 模式 | 说明 |
|---|---|
| "r" | 只读,文件必须存在 |
| "w" | 只写,文件不存在则创建,存在则清空 |
| "a" | 追加,文件不存在则创建 |
| "r+" | 读写,文件必须存在 |
| "w+" | 读写,文件不存在则创建,存在则清空 |
| "a+" | 读写追加,文件不存在则创建 |
| "rb" | 二进制只读 |
| "wb" | 二进制只写 |
| "ab" | 二进制追加 |
fclose函数
c
int fclose(FILE *stream);基本示例
c
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp = fopen("test.txt", "w");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
fprintf(fp, "Hello, World!\n");
fclose(fp);
printf("文件写入成功\n");
return 0;
}字符读写
fgetc和fputc
c
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp;
int ch;
fp = fopen("char_test.txt", "w");
if (fp == NULL) {
printf("无法创建文件\n");
return 1;
}
fputc('H', fp);
fputc('i', fp);
fputc('\n', fp);
fclose(fp);
fp = fopen("char_test.txt", "r");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
printf("文件内容: ");
while ((ch = fgetc(fp)) != EOF) {
putchar(ch);
}
fclose(fp);
return 0;
}getc和putc
c
#include <stdio.h>
int main() {
FILE *fp = fopen("test.txt", "r");
int ch;
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
while ((ch = getc(fp)) != EOF) {
putc(ch, stdout);
}
fclose(fp);
return 0;
}字符串读写
fgets和fputs
c
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp;
char str[100];
fp = fopen("string_test.txt", "w");
if (fp == NULL) {
printf("无法创建文件\n");
return 1;
}
fputs("第一行文字\n", fp);
fputs("第二行文字\n", fp);
fputs("第三行文字\n", fp);
fclose(fp);
fp = fopen("string_test.txt", "r");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
printf("文件内容:\n");
while (fgets(str, sizeof(str), fp) != NULL) {
printf("%s", str);
}
fclose(fp);
return 0;
}格式化读写
fprintf和fscanf
c
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[50];
int age;
float score;
} Student;
int main() {
FILE *fp;
Student stu = {"张三", 20, 85.5};
Student readStu;
fp = fopen("student.txt", "w");
if (fp == NULL) {
printf("无法创建文件\n");
return 1;
}
fprintf(fp, "%s %d %.1f\n", stu.name, stu.age, stu.score);
fclose(fp);
fp = fopen("student.txt", "r");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
fscanf(fp, "%s %d %f", readStu.name, &readStu.age, &readStu.score);
printf("读取的数据: 姓名=%s, 年龄=%d, 成绩=%.1f\n",
readStu.name, readStu.age, readStu.score);
fclose(fp);
return 0;
}二进制读写
fwrite和fread
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int id;
char name[50];
float score;
} Record;
int main() {
FILE *fp;
Record records[3] = {
{1, "张三", 85.5},
{2, "李四", 90.0},
{3, "王五", 78.5}
};
Record readRecords[3];
fp = fopen("records.dat", "wb");
if (fp == NULL) {
printf("无法创建文件\n");
return 1;
}
size_t written = fwrite(records, sizeof(Record), 3, fp);
printf("写入了 %zu 条记录\n", written);
fclose(fp);
fp = fopen("records.dat", "rb");
if (fp == NULL) {
printf("无法打开文件\n");
return 1;
}
size_t read_count = fread(readRecords, sizeof(Record), 3, fp);
printf("读取了 %zu 条记录\n", read_count);
for (size_t i = 0; i < read_count; i++) {
printf("ID: %d, 姓名: %s, 成绩: %.1f\n",
readRecords[i].id,
readRecords[i].name,
readRecords[i].score);
}
fclose(fp);
return 0;
}文件定位
fseek函数
c
int fseek(FILE *stream, long offset, int whence);whence参数:
| 常量 | 说明 |
|---|---|
| SEEK_SET | 文件开头 |
| SEEK_CUR | 当前位置 |
| SEEK_END | 文件末尾 |
ftell和rewind
c
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp = fopen("test.txt", "w+");
if (fp == NULL) {
printf("无法创建文件\n");
return 1;
}
fprintf(fp, "Hello, World!");
long size = ftell(fp);
printf("文件大小: %ld 字节\n", size);
rewind(fp);
char str[100];
fgets(str, sizeof(str), fp);
printf("从头读取: %s\n", str);
fseek(fp, 7, SEEK_SET);
fgets(str, sizeof(str), fp);
printf("从第7字节读取: %s\n", str);
fseek(fp, -6, SEEK_END);
fgets(str, sizeof(str), fp);
printf("从末尾前6字节读取: %s\n", str);
fclose(fp);
return 0;
}fgetpos和fsetpos
c
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp = fopen("test.txt", "w+");
fpos_t position;
if (fp == NULL) {
printf("无法创建文件\n");
return 1;
}
fprintf(fp, "Hello World\n");
fprintf(fp, "This is a test\n");
fgetpos(fp, &position);
printf("当前位置已保存\n");
rewind(fp);
char str[100];
fgets(str, sizeof(str), fp);
printf("第一行: %s", str);
fsetpos(fp, &position);
fgets(str, sizeof(str), fp);
printf("恢复位置后读取: %s", str);
fclose(fp);
return 0;
}错误处理
ferror和feof
c
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp = fopen("test.txt", "r");
if (fp == NULL) {
perror("打开文件失败");
return 1;
}
int ch;
while ((ch = fgetc(fp)) != EOF) {
putchar(ch);
}
if (feof(fp)) {
printf("\n已到达文件末尾\n");
} else if (ferror(fp)) {
printf("\n读取文件时发生错误\n");
}
clearerr(fp);
fclose(fp);
return 0;
}perror函数
c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main() {
FILE *fp = fopen("nonexistent.txt", "r");
if (fp == NULL) {
perror("错误");
printf("错误码: %d\n", errno);
return 1;
}
fclose(fp);
return 0;
}文件缓冲
setvbuf和setbuf
c
#include <stdio.h>
#include <stdlib.h>
int main() {
char buffer[BUFSIZ];
FILE *fp = fopen("buffered.txt", "w");
if (fp == NULL) {
printf("无法创建文件\n");
return 1;
}
setvbuf(fp, buffer, _IOFBF, BUFSIZ);
fprintf(fp, "这是缓冲写入的内容\n");
fflush(fp);
fclose(fp);
printf("文件写入完成\n");
return 0;
}缓冲模式:
| 模式 | 说明 |
|---|---|
| _IOFBF | 全缓冲 |
| _IOLBF | 行缓冲 |
| _IONBF | 无缓冲 |
临时文件
tmpfile和tmpnam
c
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *tmp = tmpfile();
if (tmp == NULL) {
printf("无法创建临时文件\n");
return 1;
}
fprintf(tmp, "这是临时数据\n");
rewind(tmp);
char str[100];
fgets(str, sizeof(str), tmp);
printf("从临时文件读取: %s", str);
fclose(tmp);
char filename[L_tmpnam];
tmpnam(filename);
printf("临时文件名: %s\n", filename);
return 0;
}文件删除与重命名
c
#include <stdio.h>
int main() {
FILE *fp = fopen("old.txt", "w");
if (fp != NULL) {
fprintf(fp, "测试内容\n");
fclose(fp);
}
if (rename("old.txt", "new.txt") == 0) {
printf("文件重命名成功\n");
} else {
perror("重命名失败");
}
if (remove("new.txt") == 0) {
printf("文件删除成功\n");
} else {
perror("删除失败");
}
return 0;
}实践示例
文件复制程序
c
#include <stdio.h>
#include <stdlib.h>
int copyFile(const char *src, const char *dest) {
FILE *srcFile = fopen(src, "rb");
FILE *destFile = fopen(dest, "wb");
if (srcFile == NULL || destFile == NULL) {
if (srcFile) fclose(srcFile);
if (destFile) fclose(destFile);
return -1;
}
char buffer[4096];
size_t bytesRead;
while ((bytesRead = fread(buffer, 1, sizeof(buffer), srcFile)) > 0) {
fwrite(buffer, 1, bytesRead, destFile);
}
fclose(srcFile);
fclose(destFile);
return 0;
}
int main() {
const char *source = "source.txt";
const char *destination = "copy.txt";
FILE *fp = fopen(source, "w");
if (fp != NULL) {
fprintf(fp, "这是源文件的内容\n");
fprintf(fp, "用于测试文件复制功能\n");
fclose(fp);
}
if (copyFile(source, destination) == 0) {
printf("文件复制成功\n");
} else {
printf("文件复制失败\n");
}
return 0;
}日志文件系统
c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
typedef struct {
char filename[256];
FILE *fp;
} Logger;
Logger* createLogger(const char *filename) {
Logger *logger = (Logger*)malloc(sizeof(Logger));
if (logger == NULL) return NULL;
strcpy(logger->filename, filename);
logger->fp = fopen(filename, "a");
if (logger->fp == NULL) {
free(logger);
return NULL;
}
return logger;
}
void logMessage(Logger *logger, const char *level, const char *message) {
if (logger == NULL || logger->fp == NULL) return;
time_t now = time(NULL);
char *timeStr = ctime(&now);
timeStr[strlen(timeStr) - 1] = '\0';
fprintf(logger->fp, "[%s] [%s] %s\n", timeStr, level, message);
fflush(logger->fp);
}
void logInfo(Logger *logger, const char *message) {
logMessage(logger, "INFO", message);
}
void logWarning(Logger *logger, const char *message) {
logMessage(logger, "WARNING", message);
}
void logError(Logger *logger, const char *message) {
logMessage(logger, "ERROR", message);
}
void closeLogger(Logger *logger) {
if (logger != NULL) {
if (logger->fp != NULL) {
fclose(logger->fp);
}
free(logger);
}
}
int main() {
Logger *logger = createLogger("app.log");
if (logger == NULL) {
printf("无法创建日志文件\n");
return 1;
}
logInfo(logger, "应用程序启动");
logWarning(logger, "内存使用率较高");
logError(logger, "数据库连接失败");
logInfo(logger, "应用程序关闭");
closeLogger(logger);
printf("日志已写入 app.log\n");
return 0;
}配置文件解析器
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE 256
#define MAX_ENTRIES 50
typedef struct {
char key[128];
char value[128];
} ConfigEntry;
typedef struct {
ConfigEntry entries[MAX_ENTRIES];
int count;
} Config;
void trim(char *str) {
char *start = str;
while (*start == ' ' || *start == '\t') start++;
char *end = start + strlen(start) - 1;
while (end > start && (*end == ' ' || *end == '\t' || *end == '\n' || *end == '\r')) {
end--;
}
*(end + 1) = '\0';
if (start != str) {
memmove(str, start, strlen(start) + 1);
}
}
int loadConfig(Config *config, const char *filename) {
FILE *fp = fopen(filename, "r");
if (fp == NULL) return -1;
config->count = 0;
char line[MAX_LINE];
while (fgets(line, sizeof(line), fp) != NULL && config->count < MAX_ENTRIES) {
trim(line);
if (line[0] == '\0' || line[0] == '#') continue;
char *equals = strchr(line, '=');
if (equals != NULL) {
*equals = '\0';
strcpy(config->entries[config->count].key, line);
trim(config->entries[config->count].key);
strcpy(config->entries[config->count].value, equals + 1);
trim(config->entries[config->count].value);
config->count++;
}
}
fclose(fp);
return 0;
}
const char* getValue(const Config *config, const char *key) {
for (int i = 0; i < config->count; i++) {
if (strcmp(config->entries[i].key, key) == 0) {
return config->entries[i].value;
}
}
return NULL;
}
int main() {
FILE *fp = fopen("config.ini", "w");
if (fp != NULL) {
fprintf(fp, "# 应用配置文件\n");
fprintf(fp, "server_host = localhost\n");
fprintf(fp, "server_port = 8080\n");
fprintf(fp, "debug_mode = true\n");
fprintf(fp, "max_connections = 100\n");
fclose(fp);
}
Config config;
if (loadConfig(&config, "config.ini") == 0) {
printf("配置文件加载成功,共 %d 项\n\n", config.count);
for (int i = 0; i < config.count; i++) {
printf("%s = %s\n", config.entries[i].key, config.entries[i].value);
}
printf("\n查询特定配置:\n");
printf("server_host: %s\n", getValue(&config, "server_host"));
printf("server_port: %s\n", getValue(&config, "server_port"));
} else {
printf("无法加载配置文件\n");
}
return 0;
}小结
文件操作是C语言中重要的功能:
| 函数 | 用途 |
|---|---|
| fopen/fclose | 打开/关闭文件 |
| fgetc/fputc | 字符读写 |
| fgets/fputs | 字符串读写 |
| fprintf/fscanf | 格式化读写 |
| fread/fwrite | 二进制读写 |
| fseek/ftell | 文件定位 |