You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言读取多行CSV文件示例请求:已实现单行读取

实现C语言多行CSV文件读取的完整示例

Hey! 很高兴你已经搞定了单行CSV的读取,要扩展到多行其实核心就是在单行解析逻辑外层加一个循环,持续读取直到文件末尾。不过有个容易踩坑的点:CSV标准里允许带引号的字段包含换行符,所以不能简单地按换行来分割行,得处理这种特殊场景。下面我给你一个兼顾普通情况和复杂字段的完整实现示例。

测试用CSV输入样例

id,name,description,price
1,"Alice Smith","Software Engineer, loves coding
and hiking",5000
2,"Bob Johnson","Product Manager",6500
3,"Charlie Brown","Designer, works remotely
from Paris",4800

完整的多行CSV读取实现代码

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

#define MAX_FIELD_LEN 256
#define MAX_FIELDS_PER_LINE 10

// 解析单行CSV(支持字段内换行的场景)
int parse_csv_line(FILE *fp, char fields[][MAX_FIELD_LEN], int max_fields) {
    int field_idx = 0;
    int in_quotes = 0;
    char c;
    char current_field[MAX_FIELD_LEN] = {0};
    int current_pos = 0;

    while ((c = fgetc(fp)) != EOF) {
        // 处理引号切换:进入/退出引号包裹状态
        if (c == '"') {
            in_quotes = !in_quotes;
            // 处理CSV里的转义引号:两个连续引号表示一个实际引号
            if ((c = fgetc(fp)) == '"' && in_quotes) {
                if (current_pos < MAX_FIELD_LEN - 1) {
                    current_field[current_pos++] = '"';
                }
                continue;
            }
            ungetc(c, fp); // 把非转义的字符放回输入流
            continue;
        }

        // 非引号状态下,逗号作为字段分隔符
        if (!in_quotes && c == ',') {
            if (field_idx >= max_fields) {
                fprintf(stderr, "警告:第%d个字段超过最大限制%d,截断处理\n", field_idx+1, max_fields);
                break;
            }
            strncpy(fields[field_idx++], current_field, MAX_FIELD_LEN - 1);
            memset(current_field, 0, sizeof(current_field));
            current_pos = 0;
            continue;
        }

        // 非引号状态下,换行符表示当前行结束
        if (!in_quotes && (c == '\n' || c == '\r')) {
            // 兼容Windows的\r\n换行格式
            if (c == '\r') {
                char next_c = fgetc(fp);
                if (next_c != '\n') ungetc(next_c, fp);
            }
            // 把最后一个字段存入数组
            if (current_pos > 0 && field_idx < max_fields) {
                strncpy(fields[field_idx++], current_field, MAX_FIELD_LEN - 1);
            }
            return field_idx; // 返回当前行的字段数量
        }

        // 普通字符加入当前字段,避免溢出
        if (current_pos < MAX_FIELD_LEN - 1) {
            current_field[current_pos++] = c;
        } else {
            fprintf(stderr, "警告:字段长度超过最大限制%d,截断处理\n", MAX_FIELD_LEN);
        }
    }

    // 文件结束时,处理最后一行的剩余字段
    if (current_pos > 0 && field_idx < max_fields) {
        strncpy(fields[field_idx++], current_field, MAX_FIELD_LEN - 1);
    }

    return field_idx; // 返回最后一行字段数,0表示文件读取完毕
}

// 读取多行CSV的主逻辑
int main() {
    FILE *fp = fopen("data.csv", "r");
    if (!fp) {
        perror("无法打开CSV文件");
        return 1;
    }

    char fields[MAX_FIELDS_PER_LINE][MAX_FIELD_LEN];
    int field_count;
    int line_num = 0;

    printf("CSV文件内容如下:\n");
    // 循环读取每一行,直到文件结束
    while ((field_count = parse_csv_line(fp, fields, MAX_FIELDS_PER_LINE)) > 0) {
        line_num++;
        printf("第%d行(共%d个字段):\n", line_num, field_count);
        for (int i = 0; i < field_count; i++) {
            printf("  字段%d: %s\n", i+1, fields[i]);
        }
        printf("-------------------------\n");
    }

    fclose(fp);
    return 0;
}

代码关键点说明

  • 字段内换行处理:通过in_quotes标记位判断是否处于引号包裹状态,如果是,遇到换行符不会结束当前行,而是继续读取直到匹配到闭合引号。
  • 转义引号处理:CSV标准中两个连续引号表示字段内的一个实际引号,代码会自动识别并转换为单个引号存入字段。
  • 循环读取逻辑:主函数通过while循环反复调用解析函数,直到返回0(表示文件读取完毕)。
  • 边界安全:设置了字段长度和每行最大字段数的限制,避免内存溢出,同时会输出警告提示异常情况。

内容的提问来源于stack exchange,提问作者Neios Flame Stuxnet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 06:56:45