就地修改文本文件的最佳方法是什么?

时间:2017-02-24 01:41:27

标签: python file in-place

道歉,如果已经有类似的东西被问过 - 我确实搜了一下,我可能错过了一些东西,但至少在我看来,其他问题的答案与我想要的不一样要做。

我有一个文本文件,(我们称之为'Potatoes.txt'),其中包含以下信息:

Town 1,300,
Town 2,205,
Town 3,600,
Town 4,910,
Town 5,360,

我想要做的是减少某些城镇的数量,并相应地修改文本文件。 我做了一点研究,看起来你无法修改文本文件,我需要文本文件具有相同的名称,里面只有不同的值,所以我现在正在这样做:

f = open("ModifiedPotatoes.txt","w")
f.close()

with open("Potatoes.txt","r") as file:
    for line in file:
       info = line.split(",")
       if "Town 2" or "Town 4" in line:
           info[1] -= 20
       with open("ModifiedPotatoes.txt","a"):
           infoStr = "\n" + ",".join(str(x) for x in info)
           file.write(infoStr)

f = open("Potatoes.txt","w")
f.close()

with open("ModifedPotatoes.txt","r") as file:
    for line in file:
        with open("Potatoes.txt","a") as potatoesFile:
            potatoesFile.write(line)

所以基本上我只是将旧文件覆盖为空白文件,然后从修改后的/临时文件中复制该值。有没有更好的方法来解决这个问题?

感谢您的帮助。

3 个答案:

答案 0 :(得分:0)

尝试:

mod_lines = []

with open("Potatoes.txt", "r") as f:
    for line in f:
        info = line.split(",")
        if info[0] in ("Town 2", "Town 4"):
            info[1] = int(info[1]) - 20
        mod_lines.append(info)

with open("Potatoes.txt", "w") as f:
    for m in mod_lines:
        f.write(",".join([str(x) for x in m]))

这当然不是最好的方式,但它肯定更好并且有效。

答案 1 :(得分:0)

您可以使用csv模块进行文件/字符串处理。

只需读取所有值并逐行循环,然后根据需要进行调整。然后使用csv.writer对象将它们写回新文件。

import csv
import shutil
import os

with open('potatoes.txt') as f, open('newpotatoes.txt', 'w') as fout:
    rdr = csv.reader(f)
    wrt = csv.writer(fout)

    for line in rdr:
        if line[0] in ('Town 2', 'Town 4'):
            line[1] = str(int(line[1]) - 20)
        wrt.writerow(line)

shutil.copyfile('newpotatoes.txt', 'potatoes.txt')
os.remove('newpotatoes.txt')

该行

line[1] = str(int(line[1]) - 20)

可能有点乱。之所以出现是因为来自csv的值都是字符串。所以这是一种将它转换为整数的简单方法,减去20并转换回字符串。

查看您的代码,初学者经常会犯一个错误。

if "Town 2" or "Town 4" in line:

你必须意识到这是两个单独陈述的组合,并不是你所期望的。第一个语句只是Town 2,它将始终评估为True。第二个语句是"Town 4" in line",如果字符串" Town 4"将返回True。包含在line字符串中的任何位置。

您的意图无疑是测试两个字符串是否在line中。为此,您需要显式测试两个字符串。

if "Town 2" in line or "Town 4" in line:

将按预期工作。你可以更进一步,并删除该陈述中存在的一些不雅。

你知道字符串应始终出现在字符串的第一个元素中,代码中的split info[0]之后(或我的line[0]csv做分裂)。

你可以写

if line[0] in ('Town 2', 'Town 4'):

我认为你同意的是更容易阅读和更少重复的打字,特别是如果你继续添加更多的城镇。

答案 2 :(得分:0)

可以使用模式“r +”

打开文件进行读写
data = []
with open("temp", "r+") as inFile:
    for line in inFile:
        ar = line.split(",")
        if ar[0] in ("Town 2", "Town 4"):
            data.append( (ar[0], int(ar[1]) - 20, "\n") )
        else:
            data.append(ar)

    inFile.seek(0)
    for d in data:
        inFile.write(",".join([str(x) for x in d]))
    inFile.truncate()

为了保持一切清洁,我使用seek(0)读取文件后回放文件,从缓冲区中将每一行写回来,并在关闭之前截断文件的任何剩余部分。我很想知道是否以及何时不需要这些操作。

此变体不会修改(clobber)目录中的任何其他文件,这在代码可能同时在不同输入文件上运行的情况下是有益的。我不知道一次打开一个文件是否有任何性能优势,但它可能在很小程度上有所作为。