Python中编辑文本文件中的特定行

130

假设我有一个包含以下内容的文本文件:

Dan
Warrior
500
1
0

有没有一种方法可以编辑文本文件中的特定行?现在我有以下代码:

#!/usr/bin/env python
import io

myfile = open('stats.txt', 'r')
dan = myfile.readline()
print dan
print "Your name: " + dan.split('\n')[0]

try:
    myfile = open('stats.txt', 'a')
    myfile.writelines('Mage')[1]
except IOError:
        myfile.close()
finally:
        myfile.close()

是的,我知道myfile.writelines('Mage')[1]是不正确的。但你懂我的意思,对吧?我想通过将第二行中的Warrior替换为Mage来进行编辑。但我能这样做吗?


2
我认为这篇文章涵盖了你所寻找的内容:https://dev59.com/4UvSa4cB1Zd3GeqPbhzy - Kyle Wild
2
如果您需要经常执行此类操作,您可能希望将此文件从文本转换为类似于bdb的其他格式。 - Nick Bastin
11个回答

169
你想做的是这样的事情:

# with is like your try .. finally block in this case
with open('stats.txt', 'r') as file:
    # read a list of lines into data
    data = file.readlines()

print data
print "Your name: " + data[0]

# now change the 2nd line, note that you have to add a newline
data[1] = 'Mage\n'

# and write everything back
with open('stats.txt', 'w') as file:
    file.writelines( data )
这是因为你不能直接在文件中执行"更改第二行"这样的操作。你只能覆盖(而非删除)文件的某些部分 - 这意味着新内容只会覆盖旧内容。所以,如果你在第二行上写了'Mage',则结果会变成'Mageior'。

2
嗨Jochen,语句“with open(filename, mode)”在程序退出后也会隐式地关闭文件名,对吗? - Radu
@Gabriel 谢谢,这需要注意,虽然我仍然不使用 with ... as file 语句。无论是否符合 Python 风格,我都不喜欢它 :) - Radu
1
@Radu 这只是一个习惯的问题。我以前也习惯手动关闭已打开的文件,而现在我发现使用 with 语句块会更加简洁。 - Gabriel
5
假设我们只是处理小文件,使用这种方法是否正确?否则我们可能需要大量内存来存储数据。此外,即使只有一个编辑,我们也需要重新写整个文件。 - Arindam Roychowdhury
24
如果你有一个20GB的文件,会怎么样? - Brans Ds

37
def replace_line(file_name, line_num, text):
    lines = open(file_name, 'r').readlines()
    lines[line_num] = text
    out = open(file_name, 'w')
    out.writelines(lines)
    out.close()

然后:

replace_line('stats.txt', 0, 'Mage')

18
如果文件非常大,使用此方法会将整个文件的内容加载到内存中,这可能不是一个好主意。 - Steve Ng
5
@SteveNg,你有解决你注意到的问题的方法吗?这个答案和被接受的答案都依赖于将整个文件加载到内存中。 - Blupon

28

你可以使用 fileinput 来进行原地编辑

import fileinput
for  line in fileinput.FileInput("myfile", inplace=1):
    if line .....:
         print line

17

有两种方法可以完成,选择适合您要求的:

方法 I.) 使用行号进行替换。在这种情况下,您可以使用内置函数 enumerate()

首先,在读取模式 下将所有数据存储在一个变量中。

with open("your_file.txt",'r') as f:
    get_all=f.readlines()

其次,写入文件(这是枚举发挥作用的地方)

with open("your_file.txt",'w') as f:
    for i,line in enumerate(get_all,1):         ## STARTS THE NUMBERING FROM 1 (by default it begins with 0)    
        if i == 2:                              ## OVERWRITES line:2
            f.writelines("Mage\n")
        else:
            f.writelines(line)

方法二.) 使用您想要替换的关键字:

读模式打开文件,并将其内容复制到列表中。

with open("some_file.txt","r") as f:
    newline=[]
    for word in f.readlines():        
        newline.append(word.replace("Warrior","Mage"))  ## Replace the keyword while you copy.  

"战士"已被替换为"法师",因此请将更新后的数据写入文件:

with open("some_file.txt","w") as f:
    for line in newline:
        f.writelines(line)

这是两种情况下输出的结果:

Dan                   Dan           
Warrior   ------>     Mage       
500                   500           
1                     1   
0                     0           

我尝试了两种方法;方法(I)效果不太好,但方法(II)效果很好。尽管如此,它们还是值得使用的。 - Vishal 10B

3

如果您的文本只包含一个个体:

import re

# creation
with open('pers.txt','wb') as g:
    g.write('Dan \n Warrior \n 500 \r\n 1 \r 0 ')

with open('pers.txt','rb') as h:
    print 'exact content of pers.txt before treatment:\n',repr(h.read())
with open('pers.txt','rU') as h:
    print '\nrU-display of pers.txt before treatment:\n',h.read()


# treatment
def roplo(file_name,what):
    patR = re.compile('^([^\r\n]+[\r\n]+)[^\r\n]+')
    with open(file_name,'rb+') as f:
        ch = f.read()
        f.seek(0)
        f.write(patR.sub('\\1'+what,ch))
roplo('pers.txt','Mage')


# after treatment
with open('pers.txt','rb') as h:
    print '\nexact content of pers.txt after treatment:\n',repr(h.read())
with open('pers.txt','rU') as h:
    print '\nrU-display of pers.txt after treatment:\n',h.read()

如果您的文本包含多个个体:
导入re
# creation
with open('pers.txt','wb') as g:
    g.write('Dan \n Warrior \n 500 \r\n 1 \r 0 \n Jim  \n  dragonfly\r300\r2\n10\r\nSomo\ncosmonaut\n490\r\n3\r65')

with open('pers.txt','rb') as h:
    print 'exact content of pers.txt before treatment:\n',repr(h.read())
with open('pers.txt','rU') as h:
    print '\nrU-display of pers.txt before treatment:\n',h.read()


# treatment
def ripli(file_name,who,what):
    with open(file_name,'rb+') as f:
        ch = f.read()
        x,y = re.search('^\s*'+who+'\s*[\r\n]+([^\r\n]+)',ch,re.MULTILINE).span(1)
        f.seek(x)
        f.write(what+ch[y:])
ripli('pers.txt','Jim','Wizard')


# after treatment
with open('pers.txt','rb') as h:
    print 'exact content of pers.txt after treatment:\n',repr(h.read())
with open('pers.txt','rU') as h:
    print '\nrU-display of pers.txt after treatment:\n',h.read()

如果一个人的“工作”在文本中是固定长度的,那么您只需更改与所需个人对应的“工作”部分的文本即可:这与senderle的想法相同。

但是我认为更好的方法是将个人特征记录在cPickle文件中的字典中:

from cPickle import dump, load

with open('cards','wb') as f:
    dump({'Dan':['Warrior',500,1,0],'Jim':['dragonfly',300,2,10],'Somo':['cosmonaut',490,3,65]},f)

with open('cards','rb') as g:
    id_cards = load(g)
print 'id_cards before change==',id_cards

id_cards['Jim'][0] = 'Wizard'

with open('cards','w') as h:
    dump(id_cards,h)

with open('cards') as e:
    id_cards = load(e)
print '\nid_cards after change==',id_cards

2

今晚我一直在练习文件处理,发现可以在Jochen的答案基础上提供更多的重复/多次使用功能。不幸的是,我的答案没有解决处理大文件的问题,但确实可以使小文件的处理变得更加容易。

with open('filetochange.txt', 'r+') as foo:
    data = foo.readlines()                  #reads file as list
    pos = int(input("Which position in list to edit? "))-1  #list position to edit
    data.insert(pos, "more foo"+"\n")           #inserts before item to edit
    x = data[pos+1]
    data.remove(x)                      #removes item to edit
    foo.seek(0)                     #seeks beginning of file
    for i in data:
        i.strip()                   #strips "\n" from list items
        foo.write(str(i))

0

我曾经有同样的需求,最终采用了Jinja模板。将您的文本文件更改为以下内容,并添加一个姓氏变量,然后通过传递lastname='Meg'来渲染模板,这是我能想到的最有效和最快速的方法。

Dan 
{{ lastname }} 
Warrior 
500 
1 
0

0
假设我有一个名为file_name的文件,如下所示:
this is python
it is file handling
this is editing of line

我们需要将第二行替换为“修改已完成”:
f=open("file_name","r+")
a=f.readlines()
for line in f:
   if line.startswith("rai"):
      p=a.index(line)
#so now we have the position of the line which to be modified
a[p]="modification is done"
f.seek(0)
f.truncate() #ersing all data from the file
f.close()
#so now we have an empty file and we will write the modified content now in the file
o=open("file_name","w")
for i in a:
   o.write(i)
o.close()
#now the modification is done in the file

0

编写初始数据,打印一个空的str以便更新为新数据。 在代码的最后一行插入一个空的str,这段代码可以用于迭代更新,也就是将数据附加到文本.txt文件中。

with open("data.txt", 'w') as f:
    f.write('first line\n'
            'second line\n'
            'third line\n'
            'fourth line\n'
            ' \n')

更新文本文件中的最后一行数据

my_file=open('data.txt')
string_list = my_file.readlines()
string_list[-1] = "Edit the list of strings as desired\n"
my_file = open("data.txt", "w")
new_file_contents = "". join(string_list)
my_file. write(new_file_contents)

-1
#read file lines and edit specific item

file=open("pythonmydemo.txt",'r')
a=file.readlines()
print(a[0][6:11])

a[0]=a[0][0:5]+' Ericsson\n'
print(a[0])

file=open("pythonmydemo.txt",'w')
file.writelines(a)
file.close()
print(a)

1
欢迎来到 Stack Overflow!请注意,您正在回答一个非常古老且已经有答案的问题。这里有一个关于如何回答问题的指南。 - help-info.de
@ajay-jaiswal 请明确您的问题,并提供一个最小可重现的示例和任何错误消息。您发布了代码,但没有实际问题。 - dmitryro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接