Python连接文本文件

JJ *_*eck 150 python file-io concatenation

我有一个包含20个文件名的列表['file1.txt', 'file2.txt', ...].我想编写一个Python脚本来将这些文件连接成一个新文件.我可以打开每个文件f = open(...),通过调用逐行读取f.readline(),并将每行写入该新文件.它对我来说似乎不是很"优雅",尤其是我必须阅读的部分//逐行写.

在Python中有更"优雅"的方法吗?

ins*_*get 233

这应该做到这一点

对于大文件:

filenames = ['file1.txt', 'file2.txt', ...]
with open('path/to/output/file', 'w') as outfile:
    for fname in filenames:
        with open(fname) as infile:
            for line in infile:
                outfile.write(line)
Run Code Online (Sandbox Code Playgroud)

对于小文件:

filenames = ['file1.txt', 'file2.txt', ...]
with open('path/to/output/file', 'w') as outfile:
    for fname in filenames:
        with open(fname) as infile:
            outfile.write(infile.read())
Run Code Online (Sandbox Code Playgroud)

......还有一个我想到的有趣的:

filenames = ['file1.txt', 'file2.txt', ...]
with open('path/to/output/file', 'w') as outfile:
    for line in itertools.chain.from_iterable(itertools.imap(open, filnames)):
        outfile.write(line)
Run Code Online (Sandbox Code Playgroud)

遗憾的是,这最后一种方法留下了一些打开的文件描述符,GC无论如何都要照顾它们.我只是觉得它很有趣

  • 对于大型文件,这将是非常低效的内存. (7认同)
  • 为什么要解码并重新编码整个内容?当所需的只是连接文件时,搜索换行符和所有不必要的东西。下面的 `shutil.copyfileobj` 答案会快得多。 (4认同)
  • 只是重申:这是错误的答案,shutil.copyfileobj是正确的答案. (4认同)
  • 我们认为 _large_ 文件是什么? (2认同)
  • @dee:一个文件太大,以至于它的内容不适合主内存 (2认同)

Meo*_*eow 167

使用shutil.copyfileobj.它应该更有效率.

with open('output_file.txt','wb') as wfd:
    for f in ['seg1.txt','seg2.txt','seg3.txt']:
        with open(f,'rb') as fd:
            shutil.copyfileobj(fd, wfd)
Run Code Online (Sandbox Code Playgroud)

  • 注意,如果没有EOL字符,它将合并每个文件的最后一个字符串和下一个文件的第一个字符串。就我而言,使用此代码后,结果完全损坏。我在copyfileobj之后添加了wfd.write(b“ \ n”)以得到正常结果 (5认同)
  • @Thelambofgoat我会说在这种情况下这不是纯粹的串联,但是嘿,无论什么适合你的需要。 (4认同)
  • 这是最好的解决方案.但是我想知道为什么你自己指定了块大小:文档说[`copyfileobj`](https://docs.python.org/3/library/shutil.html#shutil.copyfileobj)默认使用块. (3认同)
  • `for i in glob.glob(r'c:/Users/Desktop/folder/putty/*.txt'):` 好吧,我替换了 for 语句以包含目录中的所有文件,但我的 `output_file` 开始变得非常大就像在非常快的时间内 100 的 GB 一样。 (2认同)

aba*_*ert 53

这正是fileinput的用途:

import fileinput
with open(outfilename, 'w') as fout, fileinput.input(filenames) as fin:
    for line in fin:
        fout.write(line)
Run Code Online (Sandbox Code Playgroud)

对于这个用例,它实际上并不比仅手动迭代文件简单得多,但在其他情况下,使用单个迭代器迭代所有文件就好像它们是单个文件一样非常方便.(另外,fileinput一旦完成就关闭每个文件的事实意味着不需要withclose每个文件,但这只是一个单行节省,而不是那么大的交易.)

还有一些其他漂亮的功能fileinput,比如只需过滤每一行就可以对文件进行就地修改.


正如评论中所述,并在另一篇文章fileinput进行了讨论,因为Python 2.7将无法正常工作.这里稍作修改,使代码Python 2.7兼容

with open('outfilename', 'w') as fout:
    fin = fileinput.input(filenames)
    for line in fin:
        fout.write(line)
    fin.close()
Run Code Online (Sandbox Code Playgroud)

  • +1,我不知道``fileinput``存在,绝对是最好的方法. (3认同)
  • 示例代码对Python 2.7.10及更高版本不太有效:http://stackoverflow.com/questions/30835090/attributeerror-fileinput-instance-has-no-attribute-exit (2认同)

luc*_*asg 6

UNIX命令有什么问题?(假设你不在Windows上工作):

ls | xargs cat | tee output.txt 完成工作(你可以根据需要从子程序中使用python调用它)

  • 因为这是关于python的问题. (15认同)
  • 一般而言,这没有什么问题,但是这个答案是不对的(不要将ls的输出传递给xargs,只需将文件列表直接传递给cat:`cat * | tee output.txt`)。 (2认同)

小智 6

我不知道优雅,但这有效:

    import glob
    import os
    for f in glob.glob("file*.txt"):
         os.system("cat "+f+" >> OutFile.txt")
Run Code Online (Sandbox Code Playgroud)

  • 不是跨平台,并且会破坏包含空格的文件名 (6认同)
  • 你甚至可以避免循环:import os; os.system("cat file*.txt >> OutFile.txt") (5认同)
  • 这是不安全的; 另外,`cat`可以获取文件列表,因此无需重复调用它.您可以通过调用`subprocess.check_call`而不是`os.system`轻松地使其安全 (3认同)

小智 6

如果目录中有很多文件,那么glob2生成文件名列表可能是比手动写入文件名更好的选择。

import glob2

filenames = glob2.glob('*.txt')  # list of all .txt files in the directory

with open('outfile.txt', 'w') as f:
    for file in filenames:
        with open(file) as infile:
            f.write(infile.read()+'\n')
Run Code Online (Sandbox Code Playgroud)


小智 5

outfile.write(infile.read()) # time: 2.1085190773010254s
shutil.copyfileobj(fd, wfd, 1024*1024*10) # time: 0.60599684715271s
Run Code Online (Sandbox Code Playgroud)

一个简单的基准测试表明,shutil 性能更好。