C语言解析文件的几种方法

标准I/O——fopen

fopen通过逐行读的方式读取文件,适用于读取文本文件并且文件比较简单的方式,例如日志文件或者简单的配置文件。

#include <stdio.h>

int main() {
    FILE *fp = fopen("test.txt", "r");
    if (!fp) {
        perror("fopen");
        return 1;
    }

    char line[256];
    while (fgets(line, sizeof(line), fp)) {
        printf("Line: %s", line);
    }

    fclose(fp);
    return 0;
}

使用文件操作open

open直接打开文件读取,适合二进制文件操作字节类型的数据读取,例如日志、网络协议等类型的文件。

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    int fd = open("data.log", O_RDONLY);
    if (fd < 0) {
        perror("open");
        return 1;
    }

    unsigned char buf[128];
    ssize_t n = read(fd, buf, sizeof(buf));
    if (n > 0) {
        printf("Read %zd bytes\n", n);
    }

    close(fd);
    return 0;
}

不确定长度的读取

对于不确定内容长度的读取可以使用 getline来操作,首先使用fopen获得FILE,然后使用getline逐行读取。与fgets的区别是这里的len是动态的。

#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *fp = fopen("test.txt", "r");
    if (!fp) return 1;

    char *line = NULL;
    size_t len = 0;
    ssize_t read;

    while ((read = getline(&line, &len, fp)) != -1) {
        printf("Line: %s", line);
    }

    free(line);
    fclose(fp);
    return 0;
}

读取大文件

大文件读取就可以使用经典的mmap来操作了,mmap把文件映射到内存直接访问,非常适合高性能读取的场景。

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main() {
    int fd = open("test.txt", O_RDONLY);
    struct stat st;
    fstat(fd, &st);

    char *data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    if (data == MAP_FAILED) {
        perror("mmap");
        return 1;
    }

    write(STDOUT_FILENO, data, st.st_size); 
    munmap(data, st.st_size);
    close(fd);
    return 0;
}

读取json格式

读取json格式文件可以通过cJSon库来实现。

#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"

int main() {
    FILE *fp = fopen("config.json", "r");
    fseek(fp, 0, SEEK_END);
    long len = ftell(fp);
    rewind(fp);

    char *data = malloc(len + 1);
    fread(data, 1, len, fp);
    data[len] = '\0';
    fclose(fp);

    cJSON *root = cJSON_Parse(data);
    if (!root) {
        printf("Error before: %s\n", cJSON_GetErrorPtr());
        free(data);
        return 1;
    }

    const cJSON *name = cJSON_GetObjectItemCaseSensitive(root, "name");
    if (cJSON_IsString(name) && name->valuestring) {
        printf("Name: %s\n", name->valuestring);
    }

    cJSON_Delete(root);
    free(data);
    return 0;
}

读取yaml文件

读取yaml文件和解析得用库libyaml来实现,注意在使用前先安装库 sudo apt install libyaml-dev

#include <yaml.h>
#include <stdio.h>

int main() {
    FILE *fh = fopen("config.yaml", "r");
    yaml_parser_t parser;
    yaml_event_t event;

    yaml_parser_initialize(&parser);
    yaml_parser_set_input_file(&parser, fh);

    do {
        yaml_parser_parse(&parser, &event);

        switch (event.type) {
            case YAML_SCALAR_EVENT:
                printf("Scalar: %s\n", event.data.scalar.value);
                break;
            default:
                break;
        }

        if (event.type != YAML_STREAM_END_EVENT)
            yaml_event_delete(&event);

    } while (event.type != YAML_STREAM_END_EVENT);

    yaml_event_delete(&event);
    yaml_parser_delete(&parser);
    fclose(fh);
    return 0;
}