从多个文件写入Python会覆盖以前的内容

时间:2018-04-22 03:29:10

标签: python loops

我正在成功加载和输出我想要的方式,除了每个新的写循环都覆盖先前而不是追加,这样我只剩下循环中最后一个文件的数据。

#!/usr/bin/env python3
import glob
import xml.etree.ElementTree as ET
filenames = glob.glob("C:\\Users\\####\\Desktop\\BNC2\\[A00-A0B]*.xml")
for filename in filenames:
    with open(filename, 'r', encoding="utf-8") as content:
        tree = ET.parse(content)
        root = tree.getroot()
        outF = open("C:\\Users\\####\\Desktop\\bnc.txt", "w")
        for w in root.iter('w'):
            lemma = w.get('hw')
            pos = w.get('pos')
            tag = w.get('c5')

            outF.write(w.text + "," + lemma + "," + pos + "," + tag)
            outF.write("\n")

示例:

文件1 - a,b,c,d

文件2 - e,f,g,h

期望输出:

A,B,C,d

E,F,G,H

当前输出:

E,F,G,H

2 个答案:

答案 0 :(得分:2)

问题是您使用outF标记打开文件w,但应使用a标记。

更改

outF = open("C:\\Users\\####\\Desktop\\bnc.txt", "w")

outF = open("C:\\Users\\####\\Desktop\\bnc.txt", "a")

应该解决问题。您也可以使用w+,它不会像w那样截断文件。但完全是另一个想法(适用于w

#!/usr/bin/env python3
import glob
import xml.etree.ElementTree as ET
filenames = glob.glob("C:\\Users\\####\\Desktop\\BNC2\\[A00-A0B]*.xml")
out_lines = []
for filename in filenames:
    with open(filename, 'r', encoding="utf-8") as content:
        tree = ET.parse(content)
        root = tree.getroot()
        for w in root.iter('w'):
            lemma = w.get('hw')
            pos = w.get('pos')
            tag = w.get('c5')

            out_lines.append(w.text + "," + lemma + "," + pos + "," + tag)

with open("C:\\Users\\####\\Desktop\\bnc.txt", "w") as out_file:
    for line in out_lines:
        out_file.write("{}\n".format(line))  

答案 1 :(得分:1)

问题在于这一行:

outF = open("C:\\Users\\####\\Desktop\\bnc.txt", "w")

一遍又一遍地打开和关闭同一个文件。

在幕后:

当您调用open时,Python解释器会对操作系统进行系统调用,要求操作系统查找具有该名称的文件并返回一个整数(称为“文件描述符”或“FD”) )指的是文件。如果系统调用成功,则解释器接收FD,将FD存储在新的Python对象中,并从open函数返回该对象。

当您调用write时,解释器会将您的字符串存储在内部缓冲区中。当缓冲区填满时,或者当outF对象被销毁时(我们将看到),解释器进行系统调用,要求操作系统将缓冲区的内容写入FD引用的文件。 / p>

当没有对Python对象的引用时,解释器可以自由地对其进行垃圾收集。但首先,解释器需要在内部调用对象的__del__方法,a.k.a。对象的析构函数。文件对象的析构函数进行最后的系统调用,告诉操作系统“我不再需要这个FD了,你可以关闭文件。”

下一部分是微妙的。 open 创建返回一个新对象(我们称之为 f1 ); outF = open(...)将标识符outF分配给 f1 f1 的引用计数(分配给它的标识符数量)现在为1.在outF = open(...)的下一次迭代中,您告诉解释器您不再需要{{1引用 f1 f1 的引用计数降为0,允许垃圾收集器销毁对象并关闭文件。对outF的这一新调用会返回一个 new 对象(称之为 f2 ),这恰好会引用刚刚关闭的文件。 open被分配到 f2 f2 的引用计数现在为1.

无需一遍又一遍地打开和关闭文件。我建议在循环之前打开它

outF

这比在循环中构建列表然后在循环之后打开文件有两个优点。此方法迭代一次而不是两次,并且它需要程序内存空间中的恒定空间量(输出缓冲区的常量),而不是增长的空间量。