解析工作簿

API

从电子表格字节中提取数据

  1. var workbook = XLSX.read(data, opts);

read 方法可以从存储在 JS 字符串、”二进制字符串”、NodeJS 缓冲区或类型化数组(Uint8ArrayArrayBuffer)中的电子表格字节中提取数据。

从本地文件读取电子表格字节并提取数据

  1. var workbook = XLSX.readFile(filename, opts);

readFile 方法尝试读取所提供路径中的电子表格文件。

第二个 opts 参数是可选的。“解析选项” 涵盖了支持的属性和行为。

浏览器一般不允许通过指定文件名的方式读取文件(存在安全风险),在浏览器中运行 XLSX.readFile 会抛出错误。

必须使用 --allow-read 调用 Deno 脚本才能从文件系统读取。

示例

以下是一些常见的场景(点击每个字幕即可查看代码)。

demos 更详细地介绍了特殊部署。

示例:本地文件

XLSX.readFile 支持在 NodeJS 等平台读取本地文件。在 React Native 等其他平台中,应该使用文件数据调用 XLSX.read

“用户提交内容” 示例。 中介绍了用户拖放文件或使用文件元素的浏览器内处理

  • NodeJS
  • Electron
  • React Native
  • Photoshop
  • Deno
  • Bun

readFile 在底层使用 fs.readFileSync

  1. var XLSX = require("xlsx");var workbook = XLSX.readFile("test.xlsx");

对于 Node ESM,必须手动加载 fs

  1. import * as fs from "fs";import { readFile, set_fs } from "xlsx";set_fs(fs);const workbook = readFile("test.xlsx");

readFile 可以在渲染器进程中使用:

  1. /* From the renderer process */var XLSX = require("xlsx");var workbook = XLSX.readFile(path);

Electron API 随着时间的推移而发生变化。electron 演示 显示了完整的示例并详细说明了所需的特定于版本的设置。

React Native 演示 涵盖经过测试的插件。

readFile 在 Photoshop 和其他 ExtendScript 目标中封装了 File 逻辑。指定的路径应该是绝对路径:

  1. #include "xlsx.extendscript.js"/* Read test.xlsx from the Documents folder */var workbook = XLSX.readFile(Folder.myDocuments + "/test.xlsx");

对于用户可配置的路径,openDialog 可以显示文件选择器:

  1. #include "xlsx.extendscript.js"/* Ask user to select path */var thisFile = File.openDialog("Select a spreadsheet");var workbook = XLSX.readFile(thisFile.absoluteURI);

extendscript 演示 包括 Photoshop 和 InDesign 的完整示例。

readFile 在底层使用 Deno.readFileSync

  1. // @deno-types="https://cdn.sheetjs.com/xlsx-0.20.2/package/types/index.d.ts"import * as XLSX from 'https://cdn.sheetjs.com/xlsx-0.20.2/package/xlsx.mjs';const workbook = XLSX.readFile("test.xlsx");

读取文件的应用必须使用 --allow-read 标志来调用。

Bun readFileSync 输出应该封装在 Buffer 中:

  1. import { readFileSync } from 'fs'import { read } from './xlsx.mjs'const workbook = read(Buffer.from(readFileSync(path)));

示例:用户提交内容

此示例重点关注用户通过拖放事件、HTML 文件输入元素或网络请求提交的文件。

  • Browser
  • NodeJS
  • Deno

对于针对 Chrome 76+ 的现代网站,建议使用 File#arrayBuffer

  • Drag and Drop
  • HTML File Input Element

假设 drop_dom_element 是监听变化的 DOM 元素:

  1. <div id="drop_dom_element">Drop files here</div>

事件属性为 e.dataTransfer。该代码片段高亮了拖放示例和文件输入示例之间的区别:

  1. // XLSX is a global from the standalone scriptasync function handleDropAsync(e) { e.stopPropagation(); e.preventDefault(); const f = e.dataTransfer.files[0]; /* f is a File */ const data = await f.arrayBuffer(); /* data is an ArrayBuffer */ const workbook = XLSX.read(data); /* DO SOMETHING WITH workbook HERE */}drop_dom_element.addEventListener("drop", handleDropAsync, false);

从带有 type="file" 的 HTML INPUT 元素开始:

  1. <input type="file" id="input_dom_element">

事件属性为 e.target。该代码片段高亮了拖放示例和文件输入示例之间的区别:

  1. // XLSX is a global from the standalone scriptasync function handleFileAsync(e) { const file = e.target.files[0]; const data = await file.arrayBuffer(); /* data is an ArrayBuffer */ const workbook = XLSX.read(data); /* DO SOMETHING WITH workbook HERE */}input_dom_element.addEventListener("change", handleFileAsync, false);

https://oss.sheetjs.com/sheetjs/ 演示了 FileReader 技术。

为了获得最大兼容性 (IE10+),建议使用 FileReader 方法:

  • Drag and Drop
  • HTML File Input Element

假设 drop_dom_element 是监听变化的 DOM 元素:

  1. <div id="drop_dom_element">Drop files here</div>

事件属性为 e.dataTransfer。该代码片段高亮了拖放示例和文件输入示例之间的区别:

  1. function handleDrop(e) { e.stopPropagation(); e.preventDefault(); var f = e.dataTransfer.files[0]; /* f is a File */ var reader = new FileReader(); reader.onload = function(e) { var data = e.target.result; /* reader.readAsArrayBuffer(file) -> data will be an ArrayBuffer */ var workbook = XLSX.read(data); /* DO SOMETHING WITH workbook HERE */ }; reader.readAsArrayBuffer(f);}drop_dom_element.addEventListener("drop", handleDrop, false);

从带有 type="file" 的 HTML INPUT 元素开始:

  1. <input type="file" id="input_dom_element">

事件属性为 e.target。该代码片段高亮了拖放示例和文件输入示例之间的区别:

  1. function handleFile(e) { var file = e.target.files[0]; var reader = new FileReader(); reader.onload = function(e) { var data = e.target.result; /* reader.readAsArrayBuffer(file) -> data will be an ArrayBuffer */ var workbook = XLSX.read(e.target.result); /* DO SOMETHING WITH workbook HERE */ }; reader.readAsArrayBuffer(file);}input_dom_element.addEventListener("change", handleFile, false);

oldie 演示 显示了 IE 兼容的后备方案。

read 可以接受 NodeJS 缓冲区。readFile 可以像 formidable 一样读取由 HTTP POST 请求正文解析器生成的文件:

  1. const XLSX = require("xlsx");const http = require("http");const formidable = require("formidable");const server = http.createServer((req, res) => { const form = new formidable.IncomingForm(); form.parse(req, (err, fields, files) => { /* grab the first file */ const f = Object.entries(files)[0][1]; const path = f.filepath; const workbook = XLSX.readFile(path); /* DO SOMETHING WITH workbook HERE */ });}).listen(process.env.PORT || 7262);

server 演示 包括更高级的示例。

Drash 是 Deno 的 HTTP 服务器框架。在 POST 请求处理程序中,主体解析器可以将文件数据拉入 Uint8Array

  1. // @deno-types="https://cdn.sheetjs.com/xlsx-0.20.2/package/types/index.d.ts"import * as XLSX from 'https://cdn.sheetjs.com/xlsx-0.20.2/package/xlsx.mjs';/* load the codepage support library for extended support with older formats */import * as cptable from 'https://cdn.sheetjs.com/xlsx-0.20.2/package/dist/cpexcel.full.mjs';XLSX.set_cptable(cptable);import * as Drash from "https://cdn.jsdelivr.net/gh/drashland/drash@v2.8.1/mod.ts";class SheetResource extends Drash.Resource { public paths = ["/"]; public POST(request: Drash.Request, response: Drash.Response) { const file = request.bodyParam<Drash.Types.BodyFile>("file"); if (!file) throw new Error("File is required!"); var wb = XLSX.read(file.content); var html = XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]); return response.html(html); }}const server = new Drash.Server({ hostname: "", port: 7262, protocol: "http", resources: [ SheetResource, ],});server.run();

Deno 必须使用 --allow-net 标志运行才能启用网络请求:

  1. deno run --allow-net test-server.ts

要进行测试,请向 http://localhost:7262 提交带有附件的 POST 请求:

  1. curl -X POST -F "file=@test.xlsx" http://localhost:7262/

示例:远程文件

此示例重点介绍使用 XMLHttpRequestfetch 等 API 以及第三方库来获取文件(浏览器用语中的 “Ajax”)。

  • Browser
  • NodeJS
  • Bun
  • Deno
  • Electron

对于针对 Chrome 42+ 的现代网站,建议使用 fetch

  1. // XLSX is a global from the standalone script(async() => { const url = "https://xlsx.nodejs.cn/pres.xlsx"; const data = await (await fetch(url)).arrayBuffer(); /* data is an ArrayBuffer */ const workbook = XLSX.read(data); /* DO SOMETHING WITH workbook HERE */})();

为了获得更广泛的支持,建议使用 XMLHttpRequest 方法:

  1. var url = "https://xlsx.nodejs.cn/pres.xlsx";/* set up async GET request */var req = new XMLHttpRequest();req.open("GET", url, true);req.responseType = "arraybuffer";req.onload = function(e) { var workbook = XLSX.read(req.response); /* DO SOMETHING WITH workbook HERE */};req.send();

HTTP 下载演示 包括使用浏览器 API 和封装器库的示例。

https://oss.sheetjs.com/sheetjs/ajax.html 显示了 IE6+ 的后备方法。

NodeJS 从 18.0 版开始发布,原生支持 fetch:

  1. const XLSX = require("xlsx");const url = "https://xlsx.nodejs.cn/pres.xlsx";const data = await (await fetch(url)).arrayBuffer();/* data is an ArrayBuffer */const workbook = XLSX.read(data);

为了获得更广泛的兼容性,建议使用第三方模块。

request 需要 null 编码才能产生缓冲区:

  1. var XLSX = require("xlsx");var request = require("request");var url = "https://xlsx.nodejs.cn/pres.xlsx";request({url: url, encoding: null}, function(err, resp, body) { var workbook = XLSX.read(body); /* DO SOMETHING WITH workbook HERE */});

axios 在浏览器和 NodeJS 中的工作方式相同:

  1. const XLSX = require("xlsx");const axios = require("axios");const url = "https://xlsx.nodejs.cn/pres.xlsx";(async() => { const res = await axios.get(url, {responseType: "arraybuffer"}); /* res.data is a Buffer */ const workbook = XLSX.read(res.data); /* DO SOMETHING WITH workbook HERE */})();

Bun 原生支持 fetch。使用 NodeJS 包

  1. import * as XLSX from 'xlsx';/* load the codepage support library for extended support with older formats */import * as cptable from 'xlsx/dist/cpexcel.full.mjs';XLSX.set_cptable(cptable);const url = "https://xlsx.nodejs.cn/pres.xlsx";const data = await (await fetch(url)).arrayBuffer();/* data is an ArrayBuffer */const workbook = XLSX.read(data);

Deno 原生支持 fetch

  1. // @deno-types="https://cdn.sheetjs.com/xlsx-0.20.2/package/types/index.d.ts"import * as XLSX from 'https://cdn.sheetjs.com/xlsx-0.20.2/package/xlsx.mjs';/* load the codepage support library for extended support with older formats */import * as cptable from 'https://cdn.sheetjs.com/xlsx-0.20.2/package/dist/cpexcel.full.mjs';XLSX.set_cptable(cptable);const url = "https://xlsx.nodejs.cn/pres.xlsx";const data = await (await fetch(url)).arrayBuffer();/* data is an ArrayBuffer */const workbook = XLSX.read(data);

Deno 必须使用 --allow-net 标志运行才能启用网络请求:

  1. deno run --allow-net test-fetch.ts

主进程中的 net 模块可以向外部资源发送 HTTP/HTTPS 请求。应使用 Buffer.concat 手动连接响应:

  1. const XLSX = require("xlsx");const { net } = require("electron");const url = "https://xlsx.nodejs.cn/pres.xlsx";const req = net.request(url);req.on("response", (res) => { const bufs = []; // this array will collect all of the buffers res.on("data", (chunk) => { bufs.push(chunk); }); res.on("end", () => { const workbook = XLSX.read(Buffer.concat(bufs)); /* DO SOMETHING WITH workbook HERE */ });});req.end();

示例:可读流

推荐的方法是在内存中缓冲流,并在收集完所有数据后进行处理。正确的流解析在技术上是不可能的。

Technical details (click to show)

XLSX, XLSB, NUMBERS, and ODS files are ultimately ZIP files that contain binary and XML entries. The ZIP file format stores the table of contents (“end of central directory” record) at the end of the file, so a proper parse of a ZIP file requires scanning from the end. Streams do not provide random access into the data, so the only correct approach involves buffering the entire stream.

XLS, XLR, QPW, and Works 4 for Mac files use the “Compound File Binary Format”. It is a container format that can hold multiple “files” and “folders”. It also has a table of contents (“directory sectors”) but these can be placed anywhere in the file! The only correct approach involves buffering enough of the stream to find the full table of contents, but the added complexity has little benefit when testing against real-world files generated by various versions of Excel and other tools.

  • Browser
  • NodeJS
  • Deno

处理 ReadableStream 时,最简单的方法是缓冲流并在最后处理整个事情:

  1. // XLSX is a global from the standalone scriptasync function buffer_RS(stream) { /* collect data */ const buffers = []; const reader = stream.getReader(); for(;;) { const res = await reader.read(); if(res.value) buffers.push(res.value); if(res.done) break; } /* concat */ const out = new Uint8Array(buffers.reduce((acc, v) => acc + v.length, 0)); let off = 0; for(const u8 of buffers) { out.set(u8, off); off += u8.length; } return out;}const data = await buffer_RS(stream);/* data is Uint8Array */const workbook = XLSX.read(data);

处理可读流时,最简单的方法是缓冲流并在最后处理整个事情:

  1. var XLSX = require("xlsx");function process_RS(stream, cb) { var buffers = []; stream.on("data", function(data) { buffers.push(data); }); stream.on("end", function() { var buffer = Buffer.concat(buffers); var workbook = XLSX.read(buffer); /* DO SOMETHING WITH workbook IN THE CALLBACK */ cb(workbook); });}

在 NodeJS 的最新版本中,Promise 是首选:

  1. var XLSX = require("xlsx");/* async_RS reads a stream and returns a Promise resolving to a workbook */const async_RS = (stream) => new Promise((res, rej) => { var buffers = []; stream.on("data", function(data) { buffers.push(data); }); stream.on("end", function() { const buf = Buffer.concat(buffers); const wb = XLSX.read(buf); res(wb); });});

除了浏览器 ReadableStream API 之外,Deno 还有一个 Reader 类。

对于这些流,std 提供了 readAll 方法来将数据收集到 Uint8Array 中。此示例使用 Deno.open 从文件中读取并打印工作表名称数组:

  1. // @deno-types="https://cdn.sheetjs.com/xlsx-0.20.2/package/types/index.d.ts"import * as XLSX from 'https://cdn.sheetjs.com/xlsx-0.20.2/package/xlsx.mjs';import { readAll } from "https://deno.land/std/streams/conversion.ts";/* Simple Deno.Reader from a file */const file = await Deno.open("test.xlsx", {read: true});/* `content` will be a Uint8Array holding the full contents of the stream */const content = await readAll(file);/* Since this is a Uint8Array, `XLSX.read` "just works" */const wb = XLSX.read(content);console.log(wb.SheetNames);

包含演示 中介绍了更详细的示例

处理 JSON 和 JS 数据

JSON 和 JS 数据往往代表单个工作表。本节将使用一些实用函数来生成工作簿。

创建新工作簿

  1. var workbook = XLSX.utils.book_new();

book_new 效用函数 创建一个没有工作表的空工作簿。

API

从 JS 值数组创建工作表

  1. var worksheet = XLSX.utils.aoa_to_sheet(aoa, opts);

aoa_to_sheet 实用函数按行主序遍历 “数组的数组”,生成工作表对象。以下代码片段生成一个工作表,其中单元格 A1 设置为字符串 A1,单元格 B1 设置为 B1,等等:

  1. var worksheet = XLSX.utils.aoa_to_sheet([ ["A1", "B1", "C1"], ["A2", "B2", "C2"], ["A3", "B3", "C3"]]);

“数组的数组输入” 更详细地描述了该函数和可选的 opts 参数。

从 JS 对象数组创建工作表

  1. var worksheet = XLSX.utils.json_to_sheet(jsa, opts);

json_to_sheet 实用函数按顺序遍历 JS 对象数组,生成工作表对象。默认情况下,它将生成一个标题行和数组中每个对象一行。可选的 opts 参数具有控制列顺序和标题输出的设置。

“对象数组输入” 更详细地描述了该函数和可选的 opts 参数。

示例

“导出教程” 包含从 JSON 端点获取数据并生成工作簿的详细示例。

x-spreadsheet 是一个交互式数据网格,用于在网络浏览器中预览和修改结构化数据。

“TensorFlow.js” 涵盖了从 ML 库导出(存储在类型化数组中的数据集)创建工作表的策略。

Records from a database query (SQL or no-SQL) (click to show)

The data demo includes examples of working with databases and query results.

处理 HTML 表格

API

通过抓取页面中的 HTML TABLE 创建工作表

  1. var worksheet = XLSX.utils.table_to_sheet(dom_element, opts);

table_to_sheet 实用程序函数采用 DOM TABLE 元素并迭代行以生成工作表。opts 参数是可选的。“HTML 表格输入” 更详细地描述了该功能。

通过抓取页面中的 HTML TABLE 创建工作簿

  1. var workbook = XLSX.utils.table_to_book(dom_element, opts);

table_to_book 效用函数遵循与 table_to_sheet 相同的逻辑。生成工作表后,它会创建一个空白工作簿并附加电子表格。

options 参数支持与 table_to_sheet 相同的选项,并添加了 sheet 属性来控制工作表名称。如果缺少属性或未指定选项,则使用默认名称 Sheet1

示例

无头演示 包括使用无头 Chromium (“Puppeteer”) 和其他浏览器 (“Playwright”) 从 HTML TABLE 元素生成服务器端电子表格的示例