使用SheetJS/js-xlsx读取大型Excel文件?

9

我正在使用这个包:https://www.npmjs.com/package/xlsx

但是,我可能会有一些非常大的Excel文件,可能包含1百万行。

我测试了大约15MB的600K行Excel文件,我的代码已经在本地主机上崩溃了。

有没有办法将其流式传输?我知道文档说他们没有任何类型的流式API,但它谈到了缓冲?

 var reader = new FileReader();
    reader.onload = evt => {
      const bstr = evt.target.result;
      const wb = XLSX.read(bstr, { type: "binary" });
      const wsname = wb.SheetNames[0];
      const ws = wb.Sheets[wsname];
      const data = XLSX.utils.sheet_to_json(ws, { header: "A", defval: "" });
      });
    };
    reader.readAsBinaryString(this.file);

只需查看已打开/关闭的问题。例如,此处描述了XLS/X有哪些问题。在压缩格式的情况下,整个文件必须加载到内存中。这似乎是后端工作。 - bigless
1
您可以显示不超过限制的文件记录。或者您预计大多数文件都是15MB或更大吗? - bigless
我认为大多数文件大小都会比15MB小很多(可能只有6MB左右...我还没有测试过,所以它们也可能会有问题)。我真正需要的只是第一行,也就是标题列名称,因为有时候人们不使用正确的名称,所以我现在的做法是如果列名与预期名称不匹配,用户可以选择哪些列与我的预期名称相匹配。 - chobo2
我并没有在追随,只是找了一个例子,并开始使用它。我的想法是从电子表格中取出X行作为预览。然后,一切就准备好了,开始批量将行发送到服务器(.net core api)并保存到数据库中,同时支持尽可能大的文件(否则我将不得不制作两个版本,一个显示预览,另一个文件必须完美,并且发送到服务器并在那里处理)。 - chobo2
我发现这是一个好答案,对我有用。请尝试此链接 - Shivansh Jagga
显示剩余3条评论
3个回答

3

当我需要读取一个非常大的Excel文件(约50MB)时,我会在后端使用Excel Interop将其转换为CSV格式,这比直接从Excel文件中获取数据所需的时间更少。然后,只需通过流阅读器获取前n行即可获得所需的预览数据。将此发送到前端进行预览。这就是我会做的事情。


只翻译文本内容,不解释。它可以处理一个工作簿中的xlsx文件,但是如果有多个工作表,可能会出错。:-) - undefined
@tomy0608,它可以处理多个工作表。它为您提供了访问每个Excel工作表的API。只需将每个工作表转换为CSV文件即可。 - undefined
抱歉,我想我漏掉了关键句子“我在后端使用Excel Interop将其转换为csv”。所以,在转换之后,它可以使用流读取器工作。Excel无法使用流的原因是它是压缩文件,而csv不是。 - undefined

1

SheetJS文档推荐使用Web Workers来处理大型数据集。

来源:https://docs.sheetjs.com/docs/demos/bigdata/worker

解析和写入大型电子表格需要时间。在这个过程中, 如果SheetJS库在Web浏览器中运行,网站可能会 崩溃。

Worker提供了一种将繁重的工作卸载到本地计算机上以避免网站冻结的方法。 工作仍然在本地执行。没有数据发送到远程服务器。

将你的代码移到Web Worker中。

worker.js

/* this callback will run once the main context sends a message */
self.addEventListener('message', (e) => {
    var reader = new FileReader();
    reader.onload = evt => {
        const bstr = evt.target.result;
        const wb = XLSX.read(bstr, {type: "binary"});
        const wsname = wb.SheetNames[0];
        const ws = wb.Sheets[wsname];
        const data = XLSX.utils.sheet_to_json(ws, {header: "A", defval: ""});
        
        /* Pass the result data back */
        postMessage(data);
    }
}, false);

控制工作线程从主文件中进行

main.js

const worker = new Worker("./worker.js");
const data = {
  test: '1'
}
worker.onmessage = (response) => {
  /* response recieved from worker */
  console.log(response)
};
/* post a message to the worker */
worker.postMessage(data);

0

尝试使用流读取器

var fs = require('fs');
var XLSX = require('xlsx');
function process_RS(stream/*:ReadStream*/, cb/*:(wb:Workbook)=>void*/)/*:void*/{
var buffers = [];
stream.on('data', function(data) { buffers.push(data); });
stream.on('end', function() {
var buffer = Buffer.concat(buffers);
var workbook = XLSX.read(buffer, {type:"buffer"});

/* DO SOMETHING WITH workbook IN THE CALLBACK */
cb(workbook);

嘿,你的代码似乎不完整,process_RS是什么?这个函数被什么调用了吗? - chobo2
xlsx.read 这里不是仍然只有一个调用而不是流式调用吗?代码示例将文件作为流读入,但似乎仍然将其解析为单个(非流式)调用,我预计在处理大文件时仍可能会因OOM错误而崩溃。 - Patrick Finnigan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接