Membaca dan menimpa file dengan Python

108

Saat ini saya menggunakan ini:

f = open(filename, 'r+')
text = f.read()
text = re.sub('foobar', 'bar', text)
f.seek(0)
f.write(text)
f.close()

Tetapi masalahnya adalah file lama lebih besar dari file baru. Jadi saya berakhir dengan file baru yang memiliki bagian dari file lama di ujungnya.

compie
sumber

Jawaban:

178

Jika Anda tidak ingin menutup dan membuka kembali file tersebut, untuk menghindari kondisi balapan, Anda dapat truncatemelakukannya:

f = open(filename, 'r+')
text = f.read()
text = re.sub('foobar', 'bar', text)
f.seek(0)
f.write(text)
f.truncate()
f.close()

Fungsionalitas tersebut kemungkinan juga akan lebih bersih dan lebih aman digunakan opensebagai pengelola konteks, yang akan menutup penangan file, bahkan jika terjadi kesalahan!

with open(filename, 'r+') as f:
    text = f.read()
    text = re.sub('foobar', 'bar', text)
    f.seek(0)
    f.write(text)
    f.truncate()
nosklo.dll
sumber
Hanya untuk memperjelas pikiran saya - haruskah klip kedua Anda ada f.write(text)setelahnya f.truncate()?
volvox
2
@volvox f.write(text)sebelumnya ada f.truncate()di kode ini; itu menulis yang textpertama, jadi setelah .write()kursor file diposisikan di akhir text. Melanjutkan untuk memotong file akan menghapus byte tersisa apa pun yang mungkin dimiliki file setelah titik ini. Dalam hal ini, hasil akhirnya akan sama seperti jika Anda dipotong sebelum menulis.
nosklo
Untuk file yang sangat besar, membaca seluruh konten file ke dalam memori bisa menjadi sangat berat. Oleh karena itu, fileinputmodul dapat menjadi metode yang disukai. Ketika diteruskan inplace=1, itu akan memindahkan file ke lokasi sementara terlebih dahulu, lalu menulis file baru ke jalur nama file lama. Operasi pemindahan ini cepat pada filesystem unix, karena hanya memindahkan filesystem inode, bukan konten lengkapnya. Kemudian Anda dapat membaca & memproses setiap baris satu per satu untuk menghindari pembengkakan memori. :-)
TrinitronX
16

Mungkin akan lebih mudah dan lebih rapi untuk menutup file setelahnya text = re.sub('foobar', 'bar', text), membukanya kembali untuk ditulis (dengan demikian menghapus konten lama), dan menulis teks yang telah diperbarui ke sana.

Il-Bhima
sumber
16

The fileinputmodul memiliki inlinemodus untuk menulis perubahan ke file Anda sedang memproses tanpa menggunakan file-file sementara dll Modul ini baik merangkum operasi umum dari perulangan atas baris dalam daftar file, melalui sebuah benda yang transparan melacak nama file, nomor baris dll jika Anda ingin memeriksanya di dalam loop.

import fileinput
for line in fileinput.FileInput("file",inplace=1):
    if "foobar" in line:
         line=line.replace("foobar","bar")
    print line
anjing hantu74
sumber
0

Sejujurnya Anda dapat melihat kelas yang saya bangun ini yang melakukan operasi file dasar. Metode tulis menimpa dan menambahkan menyimpan data lama.

class IO:
    def read(self, filename):
        toRead = open(filename, "rb")

        out = toRead.read()
        toRead.close()
        
        return out
    
    def write(self, filename, data):
        toWrite = open(filename, "wb")

        out = toWrite.write(data)
        toWrite.close()

    def append(self, filename, data):
        append = self.read(filename)
        self.write(filename, append+data)
        
CodinGuy
sumber
-2

Coba tulis di file baru ..

f = open(filename, 'r+')
f2= open(filename2,'a+')
text = f.read()
text = re.sub('foobar', 'bar', text)
f.seek(0)
f.close()
f2.write(text)
fw.close()
sk7979
sumber