表格数据导出格式速查表

同一张表导出成不同格式,差别不只是后缀名:有的保留数据类型,有的只剩字符串,有的能被 Excel 直接打开,有的更适合程序读取。本页对照四种常见导出格式的取舍,并把最容易出错的 CSV 转义规则逐条列出。

原理解析

表格数据有多种载体:CSV 是纯文本、逗号分隔、无类型与样式,最适合程序间导入导出但易丢信息;XLSX 是 OOXML(ZIP 包里的 XML),支持公式、样式、多工作表;ODS 是 OpenDocument 的对应格式。

互操作坑主要在三处:日期在不同地区被解析成不同格式、编码(BOM/UTF-8)导致中文乱码、公式在跨软件时函数名/分隔符不同。导出前明确分隔符、编码与小数符号,能避免大多数「打开是乱码/数字变文本」问题。

什么时候该查这张表

这张表在你要为数据交换选择电子表格格式时有用。它把 CSV、TSV、XLSX、ODS、Parquet、Arrow 等格式按结构、类型保留能力、适用场景与常见坑并列。选型取决于数据是给人看还是给程序读。

不该查的情况:你在做数据库选型或数据仓库分层设计。电子表格格式是交换与轻量存储手段,不适合大规模分析型存储。

判断标准:先问谁来读。给人看、要在 Excel 里打开 ⇒ CSV 或 XLSX;给程序读、要保留类型与结构 ⇒ XLSX(有限)或 Parquet/Arrow(无损且快)。CSV 是最通用的交换格式,但它是扁平结构,没有多表概念也没有类型。

特别注意编码与分隔符:CSV 没有内置编码声明,用 Excel 在中文 Windows 上另存默认是 GBK,在 Mac/Linux 上另存是 UTF-8,不加 BOM 时中文会乱码。分隔符在不同地区也不同(逗号 / 分号 / 制表符)。跨系统交换时显式约定编码与分隔符,不要依赖默认值。

边界与常见陷阱

  • CSV 丢类型:数字、日期、布尔值都变成文本

    CSV 只存字符串。Excel 打开时靠猜测决定类型,于是「00123」变成 123(丢失前导零)、「2024-06-01」可能被识别为日期再按本地格式显示、TRUE 变成布尔值、大的整数 ID 变成科学计数法。往返一次(导出再导入)就可能损坏数据。只要需要保类型就不能用 CSV —— 用 XLSX,或者把类型信息写进数据(日期写成 「2024-06-01T00:00:00Z」、ID 写成字符串并明确声明)。

  • 编码与 BOM 不一致导致中文乱码

    典型场景:A 系统(Windows 中文)导出 CSV 是 GBK 无 BOM,B 系统(Linux)按 UTF-8 读 ⇒ 中文乱码;反过来 A 按 UTF-8 无 BOM 导出,Excel 双击打开 ⇒ 也乱码(Excel 对无 BOM 的 UTF-8 识别不可靠)。稳妥方案:导出时用 UTF-8 with BOM,Excel 与现代工具都能正确识别;程序读取时先检测 BOM 再决定编码;同时在交换文档里写明「编码 = UTF-8/BOM,分隔符 = 逗号」。

  • 超过 Excel 行数上限会静默截断或拒绝打开

    Excel 单表上限是 1,048,576 行 × 16,384 列,且超出后行为取决于工具:pandas 会抛异常提示,但某些导出库会静默截断只写前 1,048,575 行,用户毫无察觉。另外 Excel 的单元格最多 32,767 字符,超长文本(如一段 JSON)会被截断。超过这些量级就应该换格式:CSV 无行数上限(但内存会爆),Parquet/Arrow 才是大数据量的正解。

与相邻内容的分工

要实际转换表格格式,用站内表格与 Excel 相关工具;本页是格式选型对照。

要处理 CSV 的解析与转义(引号、换行、分隔符转义),属具体实现问题,需按 RFC 4180 处理。

要处理 Excel 公式、宏、图表等富特性,CSV 全部不支持,需要用 XLSX 并了解其限制。

若目的是排查「导出的文件在对方系统里乱码」,先确认编码与 BOM,再确认分隔符与行数上限。

实战片段

要点:① CSV 只存字符串、靠 Excel 猜类型,00123 会变成 123、日期可能被重解析、长的整数 ID 变科学计数法 —— 需要保类型就必须用 XLSX,或把类型写进数据(ISO 8601 日期、字符串 ID);② 导出 CSV 一律用 UTF-8 with BOM(Excel 双击打开才不乱码),读取时先探测 BOM 再按声明编码解码,不要靠猜(GBK 与 UTF-8 视觉接近);③ Excel 单表 1,048,576 行 × 16,384 列、单元格 32,767 字符的上限,部分导出器超限会静默截断且用户毫无察觉,超量级应改用 Parquet/Arrow;④ CSV 字段需按 RFC 4180 转义(含分隔符/引号/换行时用双引号包裹,内部引号翻倍)。

// ① CSV 没有类型信息 ⇒ 需要类型时用 XLSX,或把类型写进数据
// ❌ 直接写:00123 会被 Excel 读成 123
// ✅ 明确声明
const rows = [
  { id: '00123', createdAt: '2024-06-01T00:00:00Z', amount: '19.99', active: 'true' },
]
// 日期用 ISO 8601 带时区、ID 用字符串、金额用字符串保精度
// 导出为 CSV 时至少加表头说明类型,或直接改用 XLSX

// ② 导出 CSV 一律用 UTF-8 with BOM(Excel 双击才不会乱码)
// Node 侧手动加 BOM
function toCsvWithBom(rows) {
  const body = rows.map(r => Object.values(r).map(csvEscape).join(',')).join('
')
  return '' + body                    // BOM 前置
}
function csvEscape(v) {
  const s = String(v ?? '')
  // RFC 4180:含分隔符/引号/换行时用双引号包裹,内部引号翻倍
  return /[",
]/.test(s) ? '"' + s.replace(/"/g, '""') + '"' : s
}

// ③ 读取 CSV:先探测 BOM,再按声明的编码解码
function decodeCsv(buffer, declaredEncoding = 'utf-8') {
  const b = new Uint8Array(buffer)
  if (b[0] === 0xef && b[1] === 0xbb && b[2] === 0xbf) {
    return { encoding: 'utf-8-bom', text: new TextDecoder('utf-8').decode(b.slice(3)) }
  }
  if (b[0] === 0xff && b[1] === 0xfe) {
    return { encoding: 'utf-16le', text: new TextDecoder('utf-16le').decode(b) }
  }
  // 无 BOM ⇒ 用声明的编码(不要靠猜,中文场景 GBK 与 UTF-8 视觉接近)
  return { encoding: declaredEncoding, text: new TextDecoder(declaredEncoding).decode(b) }
}

// ④ Excel 硬限制:超限时**静默截断**是最大的坑
const XLSX_LIMITS = { rows: 1048576, cols: 16384, cellChars: 32767 }
function checkExcelLimits(data) {
  const warnings = []
  if (data.length > XLSX_LIMITS.rows - 1) {
    warnings.push('行数 ' + data.length + ' 接近上限,导出器可能静默截断')
  }
  for (const row of data) {
    for (const [k, v] of Object.entries(row)) {
      if (String(v ?? '').length > XLSX_LIMITS.cellChars) {
        warnings.push(k + ' 超单元格字符上限会被截断')
        break
      }
    }
  }
  return warnings        // 空数组才安全;非空请改用 Parquet/Arrow
}

实践注解

  • CSV 没有标准,逗号只是约定分隔符可能是逗号、分号或制表符,编码可能是 UTF-8 或 GBK,字段是否加引号也各家不同。跨系统交换应优先使用明确带 schema 的格式,或至少同时约定分隔符、引号规则与编码。
  • Excel 打开 CSV 会把长数字变成科学计数法18 位订单号以纯数字导出后,Excel 会按浮点解析并丢失末位(显示为 1.23E+17)。规避方法是导出时把该列写成带前缀的文本(如 ="123…" 或加单引号),或改用 xlsx。
  • CSV 单元格里的换行必须被引号包裹包含换行或分隔符的字段要用双引号包裹,字段内的引号需双写("")。生成时漏掉这一步,下游按行切分就会把一条记录拆成两条,且往往直到统计口径对不上才发现。

数据来源

  • RFC 4180 (CSV)
  • ECMA-376 (Office Open XML)
  • OASIS Open Document Format

上述编号、名称与定义均来自公开规范,本站不主张对规范数据本身的独创性;本页的编排方式、中文释义与实践注解由本站撰写。

四种导出格式对照

格式结构类型保留适用场景常见坑
JSON对象数组,键为表头保留数字、布尔、null接口联调、前端渲染、配置导入表头重复会覆盖;合并单元格会丢结构
CSV纯文本表格,逗号分隔全部退化为字符串数据库导入、Excel 打开、跨平台交换无类型、无编码声明,中文常乱码
HTMLtable / tr / td 标签保留文本与合并结构网页嵌入、邮件正文、富文本粘贴体积大,数值仍为文本
纯文本制表符或竖线分隔全部为字符串日志、终端粘贴、Markdown 表格含分隔符的字段需转义,否则列错位

CSV 转义规则对照

字段里只要出现逗号、换行或双引号,就必须用双引号包裹;字段内部的双引号写成两个连续双引号。

情况原始值CSV 中的写法说明
普通字段appleapple原样输出
含逗号a,b"a,b"必须用双引号包裹
含换行line1 line2"line1 line2"引号内可保留换行
含双引号say "hi""say ""hi"""内部引号写成两个
首尾空格 pad " pad "加引号以保留空格

常见问题

CSV 到底该用逗号还是制表符分隔?

看数据内容。逗号是 RFC 4180 的标准,兼容性最好,但如果数据里本身就含逗号(地址、金额、人名很常见),就必须给字段加双引号转义,处理不当会导致列错位。制表符分隔的 TSV 在文本里出现概率低得多,适合数据含逗号多的场景,代价是不是所有工具都默认识别。稳妥做法:优先用逗号并严格做引号转义;如果下游是自己控制的程序,改用 TSV 能省掉大量转义麻烦。

Excel 打开 CSV 中文为什么乱码?

因为 CSV 本身不声明编码,Excel 会按系统默认编码去猜。在中文 Windows 上默认是 GBK,而多数程序导出的 CSV 是 UTF-8,两者不一致就乱码。三种解法:导出时带 UTF-8 BOM,Excel 见到 BOM 就会按 UTF-8 解析,这是最省事的做法;或者让下游改用「数据 → 从文本导入」并手动指定 UTF-8;再或者把文件另存为 GBK,但会牺牲其他平台的兼容性。

日期导出后变成一串数字怎么办?

这是 Excel 的存储机制导致的:日期在内部就是一个从 1900-01-01 起算的序列号,显示成什么样完全取决于单元格格式。导出 CSV 时格式信息会丢失,只剩下序列号。解法是在导出前把日期列设置成文本格式,或者用 TEXT 函数先转成 yyyy-mm-dd 这样的字符串;如果导出 JSON,则要在工具侧识别日期格式并输出 ISO 8601 字符串,而不是原样取内部数值。

大表格导出很卡甚至失败,怎么处理?

瓶颈通常在浏览器内存而不是计算本身。一个 10 万行的表在解析成对象数组后,内存占用可能是原始文件的几倍,加上字符串拼接很容易触顶。实用做法:先按业务需要裁剪列和行,不要全量导出;超过几万行时改用服务端脚本处理;如果只是要给下游程序用,优先选 CSV 而不是 JSON 或 HTML,前者的内存开销和体积都小一个量级。