4

我正在使用行数作为变量来拆分文本文件。我编写此函数是为了将吐出的文件保存在临时目录中。每个文件有 400 万行,除了最后一个文件。

import tempfile
from itertools import groupby, count

temp_dir = tempfile.mkdtemp()

def tempfile_split(filename, temp_dir, chunk=4000000):
    with open(filename, 'r') as datafile:
        groups = groupby(datafile, key=lambda k, line=count(): next(line) // chunk)
        for k, group in groups:
            output_name = os.path.normpath(os.path.join(temp_dir + os.sep, "tempfile_%s.tmp" % k))
            for line in group:
                with open(output_name, 'a') as outfile:
                    outfile.write(line)

主要问题是此功能的速度。为了将一个 800 万行的文件拆分为两个 400 万行的文件,我的 windows 操作系统和 Python 2.7 的时间超过 30 分钟

4

4 回答 4

6
       for line in group:
            with open(output_name, 'a') as outfile:
                outfile.write(line)

正在打开文件,并为组中的每一行写一行。这很慢。

相反,每组写一次。

            with open(output_name, 'a') as outfile:
                outfile.write(''.join(group))
于 2013-03-26T19:53:02.460 回答
1

您可以直接在上下文管理器中使用tempfile.NamedTemporaryFile :

import tempfile
import time
from itertools import groupby, count

def tempfile_split(filename, temp_dir, chunk=4*10**6):
    fns={}
    with open(filename, 'r') as datafile:
        groups = groupby(datafile, key=lambda k, line=count(): next(line) // chunk)
        for k, group in groups:
            with tempfile.NamedTemporaryFile(delete=False,
                           dir=temp_dir,prefix='{}_'.format(str(k))) as outfile:
                outfile.write(''.join(group))
                fns[k]=outfile.name   
    return fns                     

def make_test(size=8*10**6+1000):
    with tempfile.NamedTemporaryFile(delete=False) as fn:
        for i in xrange(size):
            fn.write('Line {}\n'.format(i))

    return fn.name        

fn=make_test()
t0=time.time()
print tempfile_split(fn,tempfile.mkdtemp()),time.time()-t0   

在我的电脑上,该tempfile_split部件在 3.6 秒内运行。它是 OS X。

于 2013-03-26T20:24:06.297 回答
1

刚刚使用 800 万行文件(正常运行时间行)进行了快速测试,以运行文件的长度并将文件分成两半。基本上,一次通过获取行数,第二次通过进行拆分写入。

在我的系统上,执行第一次运行所需的时间约为 2-3 秒。要完成拆分文件的运行和写入,总时间不到 21 秒。

没有在 OP 的帖子中实现兰巴函数。下面使用的代码:

#!/usr/bin/env python

import sys
import math

infile = open("input","r")

linecount=0

for line in infile:
    linecount=linecount+1

splitpoint=linecount/2

infile.close()

infile = open("input","r")
outfile1 = open("output1","w")
outfile2 = open("output2","w")

print linecount , splitpoint

linecount=0

for line in infile:
    linecount=linecount+1
    if ( linecount <= splitpoint ):
        outfile1.write(line)
    else:
        outfile2.write(line)

infile.close()
outfile1.close()
outfile2.close()

不,它不会赢得任何性能或代码优雅测试。:) 但是除了性能瓶颈之外,lambda 函数导致文件缓存在内存中并强制交换问题,或者文件中的行非常长,我不明白为什么需要 30分钟读取/拆分 800 万行文件。

编辑:

我的环境:Mac OS X,存储是单个 FW800 连接的硬盘驱动器。文件是全新创建的,以避免文件系统缓存的好处。

于 2013-03-26T20:18:48.687 回答
0

如果您在 linux 或 unix 环境中,您可以稍微作弊并使用splitpython 内部的命令。对我有用,而且速度也很快:

def split_file(file_path, chunk=4000):

    p = subprocess.Popen(['split', '-a', '2', '-l', str(chunk), file_path,
                          os.path.dirname(file_path) + '/'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    p.communicate()
    # Remove the original file if required
    try:
        os.remove(file_path)
    except OSError:
        pass
    return True
于 2018-02-02T07:44:31.917 回答