如何解析超大 (70+ GB) .txt 文件?

had*_*909 32 bash parsing microsoft-excel

我有几个.txt文件,每个文件超过 3000 万行,任何地方都有 20 到 40 个“列”(一些以逗号分隔,一些以空格分隔,所有 ASCII 行都以换行符分隔)。我不需要所有(甚至大部分)列,其中一些列的空空格填充了NULL.

我的目标是:

  1. 删除我不需要的列
  2. 按照我认为合适的方式重新排序列(为了可读性)
  3. 管道输出到另一个 .txt 文件,列用冒号分隔

我只是将一个大文本文件拆分为大约 40 个.txt文件,每个文件包含 1,000,000 行,将它们一个一个地导入 Excel,然后使用 CONCATENATE,但这种方法对我的下一个目标没有产生任何结果。文件以逗号分隔,但仍需转.txt.csv,Excel在导入过程中卡住;即使我把它放到Excel中,主文件也会分解成200多个更小的文件以符合Excel的上限,并且做同样的事情超过200次效率不高。

我正在开发 2020 年末的 MacBook Pro,对任何编码语言都不够精通,甚至不知道从哪里开始,但我在 shell 中编写了半舒适的脚本,并且总是在学习新技巧,只是不知道从哪儿开始。

Red*_*ick 62

选择您的工具

Excel 似乎不是您想要做的事情的合适工具。

一种方法是使用不同的工具来合并或汇总数据。awk, sed,grep或者perl可能更适合这种初始处理,并创建一个较小的 CSV 文件,然后可以在 Excel 或其他工具中进行处理。

还有其他工具可能更适合完成整个工作。也许像 R 或 DBMS 之类的东西。这取决于您想对数据做什么。

为了简单地获取一堆不同的文本文件并重新排序和选择列,我会立即跳转到perl. 其他人会使用awk.

由于工具awk和工具perl可以逐行处理文件并且不需要将所有内容都存储在内存中,因此它们可以处理会阻塞其他工具的巨大文件。它们也可以出奇的快。


只是为了好玩,举个例子

有了这个数据

Apples,27,500,10.2,fruit,100,200,300
Chairs  1   501 123.78  furniture 101   201 301
Europe, 655, 502,0.0001,continent,   102, 202,302 
Run Code Online (Sandbox Code Playgroud)

我们可以产生这个输出

fruit:Apples:10.2
furniture:Chairs:123.78
continent:Europe:0.0001
Run Code Online (Sandbox Code Playgroud)

使用这个命令

perl -l -n -e "print join(':',(split(/[, \t] */))[4,0,3])" *.txt
Run Code Online (Sandbox Code Playgroud)

解释

元素 它能做什么
-l 每次打印后添加一个换行符
-n 逐行处理但不隐式打印
-e 下面是一个要执行的程序
print 打印以下表达式的结果
join(":" 列表) 从列表中创建一个字符串,在每个字符串之间使用“:”
split (/表达式/) 使用表达式将行划分为字段
[, \t] 逗号、空格或制表符后跟
* (空格星号) 0,1 或更多空格
(列表)[4,0,3] 从列表中选择第 4、第 0 和第 3 项

那一行程序等价于以下,可能更容易理解

Apples,27,500,10.2,fruit,100,200,300
Chairs  1   501 123.78  furniture 101   201 301
Europe, 655, 502,0.0001,continent,   102, 202,302 
Run Code Online (Sandbox Code Playgroud)

调用为 perl data.pl *.txt > newdata.txt

我喜欢perl并比较熟悉它的一个子集,尽管它的受欢迎程度正在下降,部分原因是它很容易编写perl很难阅读的程序。但是,它是为您的用例而设计的。任何熟悉awkpythonruby或任何大量的工具,会很容易地解决这个问题。

  • 您发现 Perl 能够快速处理 CSV 数据的原因是它只是“读取一行”、“处理该行”和“输出结果”。你输入线,然后输出线。整个文件一次性处理完毕,永远不会加载到内存中(就像在 Excel 中一样)一旦您进入 XML 或 JSON 之类的内容,结构就会比简单的数据行更复杂。这个过程必然更复杂,不太可能是*流入/流出*的努力 (5认同)
  • 我会为 Perl 再投一票,但要注意正则表达式应该谨慎使用。我认为该方法部分取决于这是“一次性”还是会再次遇到相同格式的文件,但无论如何我希望进行多次迭代才能正确处理每种类型的文件,我d 评论我所做的大量工作,因为虽然 Perl 等非常强大,但如果您必须在几个月内进行一些维护,您可能无法理解您是如何处理这项工作的。 (3认同)
  • @hadrian4909 大多数文件格式都需要正确解析。只要字段不包含特殊字符,CSV 就可以通过简单的分隔符拆分来完成。JSON 需要一个真正的 json 解析器,你可能想学习 `jq` 来从命令行处理它。SQL 文件旨在由数据库导入程序解析,这是另一个野兽。如果您有一个好的工具箱并且知道要使用哪种工具,则最好处理不同的文件类型。 (2认同)
  • @hadrian4909:Perl 可以正确解析 JSON。请参阅 [JSON::Parse](https://metacpan.org/pod/distribution/JSON-Parse/lib/JSON/Parse.pod) 但您需要更多地了解 Perl 数据结构,例如哈希散列(HoH)等等。 (2认同)

Han*_*nnu 33

操作系统不可知的答案:

只需学习一点 Python,您就会拥有一个以任何您希望的方式进行类似转换的工具。

将此输入到文件中,将其另存为例如cvt.py (最初基于此处的代码)

导入系统

导出列 = [3, 4, 5]
使用 open(sys.argv[1], 'r') 作为 fi:
    对于 fi 中的行:
        columns = line.split(',')
        打印('\t'.join(列[col] for col in exportcolumns))

安装 Python(版本 3,仅此而已!)后,您应该能够通过
Python3 cvt.py filename >newfile
其中 filename 是您的数据文件之一来运行上述内容,而 newfile 是您想要结果的位置。

正如编写的代码寻找,列分隔符,输出列 3,4,5(按该顺序),并使用制表符\t作为分隔符(在每列的末尾)。


如果您有更复杂(不一致)的柱分离,您可能会这样做

import re
Run Code Online (Sandbox Code Playgroud)

...如图所示:https : //stackoverflow.com/a/4998688/3720510


对上述内容的简短说明

  • 第一行使sys模块可用。这允许使用 sys.argvhere; 将命令行参数作为简单列表提供给脚本。
  • 第二行创建一个列表,其中包含要从输入数据中提取的列的索引。
  • with 行打开文件并使其在接下来的缩进块期间可用 - 文件在块被执行时关闭。
  • for - 对可以从文件中读取的每一行循环一次。
  • 下一行;创建一行内容的列表,在每个,.
  • 印刷品;使用“列表理解”从列表中选择列,在它们之间使用\t(制表符)将它们连接起来,然后将它们打印到sys.stdout (使用 print() 隐式),这可能是一个文件 - 如果您>在命令上使用重定向线。

  • 你不需要`iter(fi.readline, '')`。使用 `for line in fi:` 要简单得多(也更快)。 (2认同)

Džu*_*ris 15

免责声明:我实际上并没有用 70 GB 的文件尝试过这个,但我已经做了几个 GB 和超过 400 万行。

大文件的预期工作流程不是将整个文件加载到工作表中,而是连接到文件。

打开数据选项卡,选择“来自文本/CSV”,选择您的文件。当预览对话框出现时,单击“加载”按钮旁边的插入符号并选择“仅创建连接”。就是这样。这是一个更详细的教程:https : //excel.officetuts.net/en/examples/open-large-csv

使用列转换可能会有一些怪癖和更多挑战需要解决,但如果您觉得 Excel 比使用命令行工具好得多,那么值得一试。

另一种选择——如果您有权访问 Access,您也可以在那里导入和处理数据。该软件是高级用户的数据库系统。

话虽如此,我会为特定任务选择 awk。但是你至少应该对 shell 有点熟悉。


小智 9

如果您的数据格式众所周知(CSV 或其他字符分隔文件、JSON 等),您通常可以找到一个通用的命令行工具来帮助查询。

  • xsv是一种流行的逗号分隔/空格分隔数据
  • jq对 JSON 数据很流行(可在此处下载)

xsv 每秒可以处理数百 MB,具体取决于您的硬件和查询类型。