索引巨大的文本文件

时间:2011-04-11 10:21:03

标签: c++ windows linux matlab

我有一个巨大的文本文件(超过100演出),有6列数据(制表符作为分隔符)。在第一列中,我有整数值(设置中有2500个不同的值)。我需要根据第一列中的值将此文件拆分为多个较小的文件(请注意,行未进行排序)。这些较小的文件中的每一个都将用于在matlab中准备绘图。

我只有8 GB的ram。

问题是如何有效地做到这一点?有什么想法吗?

6 个答案:

答案 0 :(得分:5)

使用bash:

cat 100gigfile | while read line; do
  intval="$( echo "$line" | cut -f 1)"
  chunkfile="$( printf '%010u.txt' "$intval" )"
  echo "$line" >> "$chunkfile"
done

这会将您的100 gig文件拆分为(如您所说)2500个根据第一个字段的值命名的单个文件。您可能需要根据自己的喜好调整printf格式参数。

答案 1 :(得分:2)

单行与bash + awk:

awk '{print $0 >> $1".dat" }' 100gigfile 

这会将大文件的每一行附加到名为第一列的值+“。dat”扩展名的文件中,例如第12 aa bb cc dd ee ff行将转到12.dat文件。

答案 2 :(得分:1)

对于linux 64位(我不确定它是否适用于Windows),您可以mmap该文件,并将块复制到新文件。我认为这是最有效的方式。

答案 3 :(得分:0)

在你的shell中......

$ split -d -l <some number of lines> Foo Foo

这会将大文件Foo拆分为Foo1FooN,其中n由原始行数除以您提供给-l的值确定。在循环中迭代碎片......

编辑 ...评论中的好点...此脚本(下方)将逐行读取,分类并根据第一个字段分配给文件...

#!/usr/bin/env python
import csv

prefix = 'filename'
reader = csv.reader(open('%s.csv' % prefix, 'r'))
suffix = 0
files = {}
# read one row at a time, classify on first field, and send to a file
# row[0] assumes csv reader does *not* split the line... if you make it do so,
# remove the [0] indexing (and strip()s) below
for row in reader:
    tmp = row[0].split('\t')
    fh = files.get(tmp[0].strip(), False)
    if not fh:
        fh = open('%s%05i.csv' % (prefix, suffix), 'a')
        files[tmp[0].strip()] = fh
        suffix += 1
    fh.write(row[0])

for key in files.keys():
    files[key].close()

答案 4 :(得分:0)

最有效的方法是逐块打开,一次打开所有文件,并重新使用读取缓冲区进行写入。在提供信息时,数据中没有其他模式可用于加速它。

您将在不同的文件描述符中打开每个文件,以避免每行打开和关闭。一开始就打开它们,或者在你走的时候懒洋洋地打开它们。完成之前关闭它们。默认情况下,大多数Linux发行版只允许1024个打开的文件,所以你必须使用ulimit -n 2600,因为你有权这样做(参见/etc/security/limits.conf)。

将一个缓冲区(比如几个kb)和源文件中的原始读取分配到其中。迭代但保留控制变量。无论何时到达终点或缓冲区的末尾,都要从缓冲区写入正确的文件描述符。您需要考虑几个边缘情况,例如当读取获取换行但不足以确定应该进入哪个文件时。

如果计算出最小行大小,可以反向迭代以避免处理缓冲区的前几个字节。尽管如此,这将证明有点棘手但速度加快。

我想知道非阻塞I / O是否能解决这个问题。

答案 5 :(得分:0)

显而易见的解决方案是每次遇到新值时打开一个新文件,并保持打开直到结束。但是您的操作系统可能不允许您一次打开2500个文件。所以如果你只需要这样做一次,你就可以这样做:

  1. 浏览文件,构建所有值的列表。对此列表排序。 (如果您事先知道这些值是什么,则不需要此步骤。)
  2. 将StartIndex设置为0。
  3. 打开,比方说,100个文件(无论您的操作系统是否适合)。这些值对应于列表中的下一个100个值,从list[StartIndex]list[StartIndex+99]
  4. 浏览文件,使用list[StartIndex] <= value <= list[StartIndex+99]输入这些记录。
  5. 关闭所有文件。
  6. StartIndex添加100,如果尚未完成,请转到第3步。
  7. 所以你需要26次传递文件。