【问题标题】:Best way to read from a big CSV file without loading everything to memory using Javascript在不使用 Javascript 将所有内容加载到内存的情况下从大型 CSV 文件中读取的最佳方法
【发布时间】:2015-06-22 19:08:52
【问题描述】:

我正在使用 Atom/Electron 构建一个基于数据的视频可视化应用。每个视频都有一个对应的 CSV 文件,其中包含每个帧的信息。视频时长约100分钟,所以文件数据量很大!

我遇到的问题是加载和解析文件需要几秒钟。大多数时候这不是问题。但是我需要制作部分视频的播放列表,并且每次更改视频时加载整个 CSV 文件不是一个可行的选择。

我一直在寻找文件流选项作为 fast-csv,但我没有设法开始读取文件的任意部分。

编辑:来自 FS 文档。在这种情况下,问题是我如何知道哪个字节对应于文件中我想要的位置?

选项可以包括开始和结束值以读取一系列字节 从文件而不是整个文件。开始和结束都是 包含并从 0 开始。

您认为解决这种情况的更好和最有效的方法是什么?

具体来说:

有没有办法从 CSV 文件的任何部分开始读取流?

您认为还有另一种存储方法可以让我更好地解决这个问题吗?

更新:

最后,我通过将数据以二进制格式存储在文件中来解决这个问题。因为我知道文件有多少列,所以我可以直接从文件段中读取,而不会对性能产生任何影响。

【问题讨论】:

  • csv 中的列宽是否固定? (例如,第 1 列始终为 20 个字符)
  • 这个问题可能有用:stackoverflow.com/questions/6156501/…我对节点的了解还不够,无法确定回答,但在我看来,您希望一次在 csv 线上发送.
  • @DevinH。不,但每一列总是一个数字,所以使用某种填充并不难。理想情况下,我宁愿不这样做。我正在考虑索引每行的字节位置。并存储一个包含位置的数组。第一次加载文件时进行一些处理不会有问题。
  • 在每次读取时指定缓冲区块?这样你一次只能阅读小块(我不确定,但看起来像我的第一种方法)
  • @Bwaxxio 我认为您误解了这个问题。他似乎试图随机访问文件的一小部分,而不是流式传输整个文件。

标签: javascript node.js file csv electron


【解决方案1】:

我强烈推荐 Papaparse。它允许 CSV 的“逐行”流式传输,可以根据文件中的标头以 JSON 格式处理。

在传递给解析函数的配置对象中,您可以提供一个“step”参数,该参数是在文件逐步执行时对文件的每一行执行的函数。

注意:也可以配置为在处理非常大的 CSV 时使用工作线程以提高性能

http://papaparse.com/docs

【讨论】:

  • 好吧,这看起来很酷,但我认为与 fast-csv 或 csv-parser 之类的东西没有什么不同。它没有给我一种从 csv 的任意行开始流式传输的方法。如果我必须始终从头开始流式传输,则该解决方案不适合我的情况。你知道是否有一种方法可以跳转到给定的行吗?
  • 例如,如果您需要位于文件第 500 行中的信息,您的“步骤”函数将简单地捕获此信息,并且不会对其他行进行任何处理。从技术上讲,为了从文件中的特定点开始流式传输,仍然需要以某种容量加载文件的开头,才能知道您已经达到了所需的点。如果在特定的“步骤”上没有进行任何处理,它会以非常快的速度在文件中移动——所以我不会担心这里的性能问题。
  • 我在 nodejs 中使用 fast-csv 解析大型 csv 时出错,但这个库中没有错误(使用相同的 csv 文件)github.com/wdavidw/node-csv
【解决方案2】:

根据我的评论,Sqlite 似乎正是您想要的。从长远来看,它可能不是您的永久解决方案,但在您决定是坚持使用它还是编写自己的解决方案时,它肯定会暂时起作用。

Sqlite 的内部工作原理

Sqlite 已针对核心进行了优化,但它具有三个主要特性,使其执行速度比普通磁盘读取更快,尤其是 CSV 文件:

  1. 整个数据库(您创建的每个数据库)都存储在一个文件中,而不是多个文件或记录中。
  2. 此文件被分页为 1024 字节 (1K) 块,让您可以轻松地在数据中跳转。
  3. (实际上是 2 的一部分)整个数据库和分页系统是一棵巨大的二叉树,通常需要不到 10 次跳转才能找到任何给定的数据。所以用外行的话来说,非常快!

如果您真的有兴趣全面了解这一切,我找不到比this amazing blog post by Julia Evans 更好的解释了。

可能的缺点

除了内部工作之外,Sqlite 被设计为在用户机器上工作的客户端。如果这不是一个可行的解决方案,则可以使用一些变通方法。例如,Sqlite 可以用作 Web 服务器,但它在独立安装或混合安装中确实很受欢迎。还要记住每台客户的计算机都是不同的。一台计算机可能比另一台计算机更快地处理记录,但通常您无需担心,因为客户端计算机通常负载很小。

  • 独立版将要求一切都在客户端。这通常是 Sqlite 的使用方式。我以前用它来玩游戏,利用sqlite4java's API 用Java 连接到数据库; API 让整个体验感觉就像服务器上的 PHP 和 MySQL。由于 Sqlite 是用 C 编写的,因此您可能需要查找其他 API。
  • 混合灌输的方式与独立灌输相同,但您在程序中编写了指向实际服务器的链接。对于我帮助制作的游戏,我们会跟踪分数和用户数据等内容,然后在后台定期将其传递给实际服务器,如果我们能获得连接的话。这也适用于相反的情况。您可以启动用户,但在第一次运行时,它可以下载您需要的所有内容,然后保持自己与服务器上的内容保持同步。

总结

Sqlite 可以满足您的需求,但可能需要做一些功课才能以您需要的方式进行设置。例如 Sqlite4java 很容易安装,但学习起来很困惑,因为它们的文档很差; Stack Overflow 让我度过了难关。 Sqlite 也是一种使用它就忘记它的安装类型,所以回答你的问题,它会像蛋糕一样每秒处理 25 行,你不必担心只优化你自己的代码。

【讨论】:

    猜你喜欢
    • 2012-09-01
    • 1970-01-01
    • 2013-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-16
    相关资源
    最近更新 更多