核心是流式读取、状态机解析与缓冲控制协同:逐行读取时处理csv字段内换行,用状态机识别引号内外逗号,拆分后立即类型转换,并通过etl流水线并行加速。

核心在于避免一次性加载全部数据,用流式读取 + 状态机解析 + 合理缓冲控制三者协同。不能靠字符串分割,也不能全扔进内存,关键是要边读边识别字段边界。
用带缓冲的流逐行读取,不卡死文件句柄
无论用 Go 的 bufio.Scanner、Java 的 BufferedReader 还是 C 的 fgets,都必须设置合理缓冲区大小(如 64KB–256KB),防止小缓冲导致系统调用频繁。特别注意:不要用 readLine() 类接口直接读到换行符就停——CSV 字段内可能含换行符(被双引号包裹),此时需继续读下一行并拼接,直到找到匹配的结束引号。
- Go 中推荐用
scanner.Split(bufio.ScanLines)配合手动跨行合并逻辑 - Java 可封装
BufferedReader,遇到引号开头的行时循环readLine()直至引号闭合 - C 语言需自己维护读取状态,用
realloc动态扩展行缓冲,同时跳过\r兼容 Windows 换行
字段拆分必须用状态机,不是简单 split
逗号是否为分隔符,取决于当前是否处于引号内。靠 strtok 或 split(",") 会把 "Beijing, China" 错拆成两段。正确做法是遍历每个字符,维护一个“是否在引号中”的布尔状态,并处理转义引号(两个连续 " 视为一个)。
使用 qbo-mileage CLI 及用户凭证,从 Airtable、Outlook 或 Google Calendar 记录生成 QuickBooks Online 里程 CSV 文件。
- 状态包括:空闲(Idle)、解析中(Parsing)、引号内(InQuotes)、转义中(Escaping)
- 遇到起始引号进入
InQuotes;再遇引号时,检查下一个是否也是引号——是则进入Escaping,跳过一个;否则退出引号状态 - 仅当不在引号内且遇到逗号时,才切分字段
拆分后立即转换类型,避免字符串堆压
读出字段字符串后,不要缓存大量 string 或 std::vector<:string></:string>。应立刻尝试转成目标类型(如 int64、float64、时间戳),失败则记录错误行号或丢弃。C/Go 中可用 strconv.ParseInt 或 strtol,Java 推荐 Long.parseLong 并捕获 NumberFormatException。
- 整数字段优先用
int64(防溢出),避免atoi或Integer.parseInt默认int32 - 浮点字段注意精度损失,必要时保留原始字符串供后续高精度计算
- 空字段、全空白字段按业务规则统一处理(如转为 NULL 或默认值)
结合 goroutine 或线程做流水线并行(可选但强烈建议)
对 GB 级 CSV,单线程读+解析+转换仍是瓶颈。可拆成 Extract → Transform → Load 三级 pipeline:
- Extract 阶段:1 个 goroutine / 线程顺序读文件,发每行到
chan string(缓冲 1024) - Transform 阶段:N 个 worker 并发消费行,执行状态机拆分 + 类型转换,输出结构体切片或 map
- Load 阶段:M 个 worker 异步写数据库或发 Kafka,避免阻塞上游
- 注意 channel 缓冲大小和 worker 数量需压测调优,过多 goroutine 反而增加调度开销










