在Python中高效地拆分大文本文件的方法

7 投票
2 回答
3175 浏览
提问于 2025-04-17 18:00

这是一个之前的问题,讨论如何提高Python中一个函数的运行速度。我需要找到一种高效的方法来分割我的文本文件。

我有一个文本文件(超过32GB),没有排序

....................
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)

我需要将这个大约32GB的文件切分成n (= len(tiles_id))个文件。

我可以在不排序的情况下完成这个操作,但需要读取文件n次。因此,我希望找到一种高效的文件切分方法,从(0,0) (= tiles_id[0])开始。这样我就可以只读取一次切分后的文件。

2 个回答

1

我在网上随便搜了一下,找到了这个方法,是在ActiveState网站上的。虽然里面没有提供性能对比,但看起来这个方法可以完成任务。

简单来说,这个方法似乎和@Ellioh提到的建议差不多,你可以直接使用这个现成的方案,不用再自己重新发明轮子了。

5

对于一个32GB的文件来说,排序几乎是不可能的,无论你是用Python还是命令行工具(比如sort)。虽然数据库看起来很强大,但如果你不想用数据库,我建议你可以把源文件按照瓦片ID分割成多个小文件。

具体做法是:你读取一行数据,然后用瓦片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)

最完美的做法是,当打开的文件数量达到上限时,关闭一些文件并把它们从字典中移除。

撰写回答