Skip to content

文件操作

概述

文件操作是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文件定位

导航