使用Python从文本文件中删除一行

时间:2012-06-28 17:34:20

标签: python file-io

我有一个文件,其中每行以数字开头。用户可以通过键入用户想要删除的行的编号来删除行。

我遇到的问题是设置打开它的模式。当我使用a+时,原始内容仍然存在。但是,添加到文件末尾的是我想要保留的行。另一方面,当我使用w+时,整个文件将被删除。我确信有一个更好的方法,而不是用w+模式打开它,删除所有内容,然后重新打开它并附加行。

 def DeleteToDo(self):
    print "Which Item Do You Want To Delete?"
    DeleteItem = raw_input(">") #select a line number to delete
    print "Are You Sure You Want To Delete Number" + DeleteItem + "(y/n)"
    VerifyDelete = str.lower(raw_input(">"))
    if VerifyDelete == "y":
        FILE = open(ToDo.filename,"a+") #open the file (tried w+ as well, entire file is deleted)
        FileLines = FILE.readlines() #read and display the lines
        for line in FileLines:
            FILE.truncate()
            if line[0:1] != DeleteItem: #if the number (first character) of the current line doesn't equal the number to be deleted, re-write that line
                FILE.write(line)
    else:
        print "Nothing Deleted"

这是典型文件的样子

1. info here
2. more stuff here
3. even more stuff here

5 个答案:

答案 0 :(得分:2)

当您打开文件进行书写时,您会破坏文件(删除其当前内容并启动新文件)。您可以通过阅读open()命令的文档来找到它。

当您打开要追加的文件时,您不会破坏该文件。但是如何删除一行呢?文件是存储在存储设备上的字节序列;没有办法删除一行,并让所有其他行自动“滑下”到存储设备上的新位置。

(如果您的数据存储在数据库中,您实际上只能从数据库中删除一个“行”;但文件不是数据库。)

因此,传统的解决方法是:从原始文件中读取,然后将其复制到新的输出文件中。复制时,执行任何所需的编辑;例如,您可以通过不复制那一行来删除一行;或者您可以通过将其写入新文件来插入一行。

然后,一旦您成功编写了新文件并成功关闭它,如果没有错误,您可以继续将新文件重命名为与旧文件相同的名称(这会破坏旧文件)。

在Python中,您的代码应该是这样的:

import os

# "num_to_delete" was specified by the user earlier.

# I'm assuming that the number to delete is set off from
# the rest of the line with a space.

s_to_delete = str(num_to_delete) + ' '
def want_input_line(line):
    return not line.startswith(s_to_delete)

in_fname = "original_input_filename.txt"
out_fname = "temporary_filename.txt"

with open(in_fname) as in_f, open(out_fname, "w") as out_f:
    for line in in_f:
        if want_input_line(line):
            out_f.write(line)

os.rename(out_fname, in_fname)

请注意,如果您碰巧有一个名为temporary_filename.txt的文件,则会被此代码破坏。我们真的不关心文件名是什么,我们可以让Python使用tempfile模块为我们编制一些独特的文件名。

任何最新版本的Python都允许您在单个with语句中使用多个语句,但如果您碰巧使用Python 2.6或其他东西,您可以嵌套两个with语句以获得相同的效果:

with open(in_fname) as in_f:
    with open(out_fname, "w") as out_f:
        for line in in_f:
            ... # do the rest of the code

另外,请注意我使用.readlines()方法获取输入行,因为.readlines()将文件的全部内容一次性读入内存,如果文件非常大,这将很慢或甚至可能不起作用。您只需使用从for返回的“文件对象”编写open()循环;这将为您提供一行一行,您的程序甚至可以处理非常大的文件。

编辑:请注意,我的答案是假设你只想做一个编辑步骤。正如@jdi在评论中指出的另一个答案,如果你想允许“交互式”编辑,用户可以删除多行,或插入行等,那么最简单的方法就是将所有行读入内存.readlines(),在结果列表中插入/删除/更新/任何内容,然后只在编辑完成后一次将列表写入文件。

答案 1 :(得分:1)

不是将所有行逐个写入文件,而是从内存中删除行(使用readlines()读取文件),然后一次性将内存写回磁盘。这样你就可以获得你想要的结果,而且你不必堵塞I / O.

答案 2 :(得分:1)

def DeleteToDo():
    print ("Which Item Do You Want To Delete?")
    DeleteItem = raw_input(">") #select a line number to delete
    print ("Are You Sure You Want To Delete Number" + DeleteItem + "(y/n)")
    DeleteItem=int(DeleteItem) 
    VerifyDelete = str.lower(raw_input(">"))
    if VerifyDelete == "y":
        FILE = open('data.txt',"r") #open the file (tried w+ as well, entire file is deleted)
        lines=[x.strip() for x in FILE if int(x[:x.index('.')])!=DeleteItem] #read all the lines first except the line which matches the line number to be deleted
        FILE.close()
        FILE = open('data.txt',"w")#open the file again
        for x in lines:FILE.write(x+'\n')    #write the data to the file

    else:
        print ("Nothing Deleted")
DeleteToDo()

答案 3 :(得分:0)

您无需检查文件中的行号,您可以执行以下操作:

def DeleteToDo(self):
    print "Which Item Do You Want To Delete?"
    DeleteItem = int(raw_input(">")) - 1
    print "Are You Sure You Want To Delete Number" + str(DeleteItem) + "(y/n)"
    VerifyDelete = str.lower(raw_input(">"))
    if VerifyDelete == "y":
        with open(ToDo.filename,"r") as f:
            lines = ''.join([a for i,a in enumerate(f) if i != DeleteItem])

        with open(ToDo.filename, "w") as f:
            f.write(lines)
    else:
        print "Nothing Deleted"

答案 4 :(得分:0)

你可以mmap文件......在阅读完合适的文档后......