【问题标题】:Efficent way to split a large text file in python [duplicate]在python中拆分大文本文件的有效方法[重复]
【发布时间】:2013-03-06 23:37:42
【问题描述】:

这是以前的question 在哪里提高python中函数的时间性能我需要找到一种有效的方法来拆分我的文本文件

我有以下文本文件(超过 32 GB)未排序

....................
0 274 593869.99 6734999.96 121.83 1,
0 273 593869.51 6734999.92 121.57 1,
0 273 593869.15 6734999.89 121.57 1,
0 273 593868.79 6734999.86 121.65 1,
0 272 593868.44 6734999.84 121.65 1,
0 273 593869.00 6734999.94 124.21 1,
0 273 593868.68 6734999.92 124.32 1,
0 274 593868.39 6734999.90 124.44 1,
0 275 593866.94 6734999.71 121.37 1,
0 273 593868.73 6734999.99 127.28 1,
.............................

第一列和第二列是网格中 x,y,z 点的位置 ID(例如:0 -273)。

def point_grid_id(x,y,minx,maxy,distx,disty):
    """give id (row,col)"""
    col = int((x - minx)/distx)
    row = int((maxy - y)/disty)
    return (row, col)

(minx, maxx) 是我的网格的原点,大小为distx,disty。 Id 瓦片的数量是

tiles_id = [j for j in np.ndindex(ny, nx)] #ny = number of row, nx= number of columns 
from [(0,0),(0,1),(0,2),...,(ny-1,nx-1)]
n = len(tiles_id)

我需要在 n (= len(tiles_id)) 个文件中分割 ~32 GB 文件。

我可以在不排序但读取文件 n 次的情况下执行此操作。出于这个原因,我希望为(0,0) (= tiles_id[0]) 开头的文件找到一种有效的拆分方法。之后我只能读取一次拆分的文件。

【问题讨论】:

  • 不使用python怎么样?
  • 不确定使用 Python 对这种大小的文件进行排序的效率有多高。
  • 那么,我希望你能在它运行的时候读到一些东西。
  • 免费周末在山上远足,远离 PC :)。我知道 Python 很慢,但如果算法需要几天时间也没关系
  • @Gianni: I LOVE Python!! ,是的,我看得出来,爱是如此盲目以至于你看不到它的弱点

标签: python performance algorithm sorting optimization


【解决方案1】:

无论您使用 Python 还是命令行工具 (sort),对于 32GB 的文件几乎都无法进行排序。数据库似乎太强大了,但可以使用。但是,如果您不愿意使用数据库,我建议只需使用 tile id 将源文件拆分为文件。

您读取一行,从一个 tile id 中创建一个文件名,并将该行附加到文件中。并继续,直到源文件完成。它不会太快,但至少它有 O(N) 的复杂度,不像排序。

当然,文件的单独排序和连接是可能的。排序 32GB 文件的主要瓶颈应该是内存,而不是 CPU。

我想是这样的:

def temp_file_name(l):
    id0, id1 = l.split()[:2]
    return "tile_%s_%s.tmp" % (id0, id1)

def split_file(name):
    ofiles = {}
    try:
        with open(name) as f:
            for l in f:
                if l:
                    fn = temp_file_name(l)
                    if fn not in ofiles:
                        ofiles[fn] = open(fn, 'w')
                    ofiles[fn].write(l)
    finally:
        for of in ofiles.itervalues():
            of.close()

split_file('srcdata1.txt')

但是如果图块很多,超过了可以打开的文件数量,你可以这样做:

def split_file(name):
    with open(name) as f:
        for l in f:
            if l:
                fn = temp_file_name(l)
                with open(fn, 'a') as of:
                    of.write(l)

而最完美主义的方法是在达到打开文件数量限制后关闭一些文件并从字典中删除它们。

【讨论】:

  • 然后您可以轻松地对单个文件进行排序。
  • 但是我只需要读一次吗?
  • 当然可以。您必须使用多文件排序和合并,但这是可能的。
  • 你真的需要排序吗?你宁愿需要分成瓷砖,除非我错了。拆分很容易。但如果需要完全排序,您将能够对每个文件进行排序并将它们连接起来。
  • 我的示例文件包含一个空行。 :-) 如果你不能,你可以安全地省略“if l:”。
【解决方案2】:

一个快速的谷歌将我带到 ActiveState 代码中的this recipe。它没有提供任何性能比较,但它似乎完成了这项工作。

简而言之,它似乎按照@Ellioh 的建议进行操作,而且您有一个现成的食谱,您可能不必重新发明*。

【讨论】: