4

各行が数字で始まるファイルがあります。ユーザーは、削除したい行の番号を入力することにより、行を削除できます。

私が抱えている問題は、それを開くためのモードを設定することです。を使用する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
4

5 に答える 5

2

書き込み用にファイルを開くと、ファイルが上書きされます (現在の内容が削除され、新しいファイルが開始されます)。これは、コマンドのドキュメントを読むことで確認できますopen()

追加するためにファイルを開く場合、ファイルを壊すことはありません。しかし、どうすれば 1 行だけを削除できますか? ファイルは、ストレージ デバイスに格納された一連のバイトです。1 つの行を削除して、他のすべての行をストレージ デバイスの新しい位置に自動的に "スライド ダウン" させる方法はありません。

(データがデータベースに格納されている場合、実際にはデータベースから「行」を 1 つだけ削除できますが、ファイルはデータベースではありません。)

したがって、これを解決する従来の方法: 元のファイルから読み取り、それを新しい出力ファイルにコピーします。コピーするときに、必要な編集を行います。たとえば、その行をコピーしないだけでその行を削除できます。または、新しいファイルに書き込んで行を挿入することもできます。

次に、新しいファイルを正常に書き込み、正常に閉じたら、エラーがなければ、新しいファイルの名前を古いファイルと同じ名前に戻します (これにより、古いファイルが上書きされます)。

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、このコードによって上書きされることに注意してください。実際、ファイル名が何であるかは気にしませんtempfile。モジュールを使用して、Python に一意のファイル名を作成するように依頼できます。

最近のバージョンの Python では、1 つのwithステートメントで複数のステートメントを使用できますが、Python 2.6 などを使用している場合は、2 つの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

また、このメソッドを使用して入力行を取得しなかったことに注意してください。これは、ファイルの内容全体を一度にメモリに読み込むためです。ファイルが非常に大きい場合、これは遅くなるか、機能しなくなる可能性さえあります。から返された「ファイルオブジェクト」を使用して、単純にループを書くことができます。これにより、一度に 1 行が得られ、プログラムは非常に大きなファイルでも機能します。.readlines().readlines()foropen()

編集:私の答えは、1つの編集ステップを実行したいだけだと仮定していることに注意してください。@jdiが別の回答のコメントで指摘したように、ユーザーが複数の行を削除したり、行を挿入したりできる「インタラクティブな」編集を許可したい場合、実際には最も簡単な方法は、を使用してすべての行をメモリに読み込むことです.readlines()、結果のリストで挿入/削除/更新/その他を行い、編集がすべて完了したら、リストをファイルに1回だけ書き出します。

于 2012-06-28T19:13:34.780 に答える
1

すべての行を 1 行ずつファイルに書き出す代わりに、(readlines() を使用してファイルを読み取った) メモリから行を削除し、メモリを一度にディスクに書き戻します。そうすれば、必要な結果が得られ、I/O を詰まらせる必要がなくなります。

于 2012-06-28T17:39:25.620 に答える
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()
于 2012-06-28T17:49:46.597 に答える
0

あなたmmapはファイルを...適切なドキュメントを読んだ後...

于 2012-06-28T21:08:50.950 に答える
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"
于 2012-06-28T19:32:07.963 に答える