连接python中多个大文件的每第n行

时间:2016-11-01 11:52:55

标签: python python-3.x

考虑以下不同大小的文件:

FILE1.TXT

sad
mad
rad
cad
saf

FILE2.TXT

er
ar
ir
lr
gr
cf

file3.txt

1
2
3
4
5
6
7
8
9

我正在寻找一种方法来连接所有文件中的每一行,以便所需的输出文件为:

sad
er
1
rad
ir
3
saf
gr
5
7
9

我成功设法使用以下脚本为我的测试文件执行此操作:

import os    

globalList = list()

for file in os.listdir('.'):
    if file.endswith('txt'):
        with open(file, 'r') as inf:
            l = list()
            n=0
            for i, line in enumerate(inf):
                if i == n:
                    nline=line.strip()
                    l.append(nline)
                    n+=2

            globalList.append(l)

            inf.close()

ouf = open('final.txt', 'w')

for i in range(len(max(globalList, key=len))):
    for x in globalList:
        if i < len(x):
            ouf.write(x[i])
            ouf.write('\n')
        else:
            pass

ouf.close()

上述脚本适用于小型测试文件。但是,当我尝试使用我的实际文件(数百个包含数百万行的文件)时,我的计算机很快耗尽内存并且脚本崩溃了。有没有办法克服这个问题,即避免在RAM中存储这么多信息,并以某种方式直接在输出文件中写入行?谢谢!

5 个答案:

答案 0 :(得分:3)

在python3中尝试此代码:

script.py

from itertools import  zip_longest
import glob


every_xth_line = 2
files = [open(filename) for filename in glob.glob("*.txt")]

with open('output.txt', 'w') as f:
    trigger = 0
    for lines in zip_longest(*files, fillvalue=''):
        if not trigger:
            for line in lines:
                f.write(line)
        trigger = (trigger + 1) % every_xth_line

output.txt的

sad
er
1
rad
ir
3
saf
gr
5
7
9

open本身实际上可以迭代。 zip_longest确保脚本运行直到最长的文件用完为止,并且fillvalues只是作为空字符串插入。

必须使用触发器来分隔均匀和不均匀的文件,通过将every_xth_line设置为其他内容,可以通过简单的模运算实现更通用的解决方案。

关于可扩展性:

我尝试生成大型文件:

cat /usr/share/dict/words > file1.txt
cat /usr/share/dict/words > file2.txt
cat /usr/share/dict/words > file3.txt

一些复制粘贴后:

68M Nov  1 13:45 file.txt
68M Nov  1 13:45 file2.txt
68M Nov  1 13:45 file3.txt

运行它:

time python3 script.py
4.31user 0.14system 0:04.46elapsed 99%CPU (0avgtext+0avgdata 9828maxresident)k
0inputs+206312outputs (0major+1146minor)pagefaults 0swaps

结果:

101M Nov  1 13:46 output.txt

答案 1 :(得分:0)

我相信这样的事情就是你想要的。请注意,我不会存储行数组,但在需要时会懒惰地读取行。它有助于节省内存

import os


files = [open(file) for file in os.listdir('.') if file.endswith('txt')]
with open('final.txt', 'w') as f:
    while 1:
        for file in files:
            try:
                f.write(next(f))
            except StopIteration:
                break
            if YourCounterFunction:
                break

答案 2 :(得分:0)

尝试一次阅读一行。如果我们可以弄清楚如何不短路,或者我们可以通过没有作为get_odd的返回

#!/usr/bin/env python3

def get_odd(f):
    x = f.readline().strip()
    if x: print(x)
    return f.readline() or ""

with open("file1.txt", 'r') as x:
    with open("file2.txt", 'r') as y:
        with open("file3.txt", 'r') as z:
            while ("" != (get_odd(x) + get_odd(y) + get_odd(z))):
                pass

答案 3 :(得分:0)

我会为奇数行创建一个生成器。然后获取我想要的行并将它们写入文件。这是代码:

def numberLine():
    number = -2
    while True:
        number += 2
        yield number

def writeNewFile(files):
    with open("newFile.txt", 'w') as theFile:
        for line in numberLine():
            if files:
                for file in files:
                    try:
                        with open(file) as openFile:
                            theFile.write(openFile.readlines()[line])
                    except IndexError:
                        files.remove(file)
                        continue
            else:
                break

现在您需要做的就是将包含文件的列表传递到writeNewFile函数中! writeNewFile([file for file in os.listdir() if file.endswith('txt')])

答案 4 :(得分:0)

此脚本处理任意数量的文件并打印每个文件的每一行,直到所有文件都达到EOF。

#!/usr/bin/env python

import sys

def every_second(files):
    fds = [open(f,'r') for f in files]

    i = 0
    end = 0
    num = len(fds)
    while end < num:
        for fd in fds:
            try:
                l = fd.readline()
            except:
                continue
            if l == "":
                end += 1
                fd.close()
            elif i%2 == 0:
                sys.stdout.write(l)
        i += 1

if __name__ == '__main__':
    every_second(sys.argv[1:])