Cara yang benar untuk menulis baris ke file?

1069

Saya sudah terbiasa melakukannya print >>f, "hi there"

Namun, tampaknya print >>sudah mulai ditinggalkan. Apa cara yang disarankan untuk melakukan baris di atas?

Pembaruan : Mengenai semua jawaban dengan "\n"... apakah ini universal atau khusus-Unix? IE, yang harus saya lakukan "\r\n"di Windows?

Yaroslav Bulatov
sumber
11
"\ n" tidak spesifik Unix. Ketika file dibuka dalam mode teks (default), itu diterjemahkan secara otomatis ke baris yang benar berakhir untuk platform saat ini. Menulis "\ r \ n" akan menghasilkan "\ r \ r \ n" yang salah.
D Coetzee
Cukup tambahkan pernyataan print ord (os.linesep) untuk melihat kode ascii (10 pada kebanyakan sistem UNIX)
Stefan Gruenwald
Menurut Anda mengapa itu sudah usang?
xxx ---

Jawaban:

1153

Ini harus sesederhana:

with open('somefile.txt', 'a') as the_file:
    the_file.write('Hello\n')

Dari Dokumentasi:

Jangan gunakan os.linesepsebagai terminator garis saat menulis file dibuka dalam mode teks (default); gunakan tunggal '\ n' sebagai gantinya, di semua platform.

Beberapa bacaan yang bermanfaat:

Johnsyweb
sumber
37
Contoh ini lebih baik daripada contoh buka / tutup. Menggunakan withadalah cara yang lebih aman untuk mengingat untuk menutup file.
Eyal
18
Saya tidak perlu menelepon the_file.close()?
Hussain
19
tidak, Anda tidak: stackoverflow.com/questions/3012488/…
Tal Jerome
@Johnsyweb Mengapa Anda mengatakan "os.linesep. Ada banyak hal bagus di os!", Ketika Anda sebelumnya di posting merekomendasikan untuk tidak menggunakannya? Saya mencurigai hasil edit di sini, dan itu mungkin menjadi alasan untuk suara turun.
Kuda SMith
1
@ user3226167: Itu poin yang menarik. Tetapi mengapa Anda membuka file biner untuk menulis teks biasa?
Johnsyweb
961

Anda harus menggunakan print()fungsi yang tersedia sejak Python 2.6+

from __future__ import print_function  # Only needed for Python 2
print("hi there", file=f)

Untuk Python 3 Anda tidak perlu import, karena print()fungsinya adalah default.

Alternatifnya adalah menggunakan:

f = open('myfile', 'w')
f.write('hi there\n')  # python will convert \n to os.linesep
f.close()  # you can omit in most cases as the destructor will call it

Mengutip dari dokumentasi Python mengenai baris baru:

Pada keluaran, jika baris baru Tidak ada, '\n'karakter apa pun yang ditulis diterjemahkan ke pemisah garis default sistem os.linesep,. Jika baris baru '', tidak ada terjemahan yang terjadi. Jika baris baru adalah salah satu dari nilai hukum lainnya, '\n'karakter apa pun yang ditulis diterjemahkan ke string yang diberikan.

Sorin
sumber
35
-1 "Jika Anda ingin memastikan, tambahkan os.linesep ke string, bukan \n" akan memerlukan newline = "" jika tidak Anda akan mendapatkan \r\r\nWindows. Tidak ada alasan untuk lanjut dengan os.linesep sama sekali.
John Machin
7
@Sorin: Edit Anda untuk menambahkan mode tulis tentu saja merupakan peningkatan. Namun Anda anehnya tetap tidak tahu tentang os.linesep. Lihat jawaban saya. Omong-omong, dokumentasi yang Anda kutip adalah untuk 3.x, tetapi bagian ini juga berlaku untuk 2.x dalam mode teks: karakter '\ n' apa pun yang ditulis diterjemahkan ke pemisah garis default sistem, os.linesep * . .. Windows: penulisan os.linesep sama dengan tulisan \r\nyang berisi \nyang diterjemahkan ke os.linesep yang merupakan \r\nhasil akhirnya \r\r\n.
John Machin
7
@ John kau benar, aku mengoreksi bug os.linesep. Terima kasih.
Sorin
3
Untuk menambahkan open('myfile','a')bukan open('myfile','w')?
NeDark
6
@BradRuderman Itu bagian dari standar POSIX untuk apa yang merupakan "baris" dalam file teks, yaitu setiap baris dalam file teks harus diakhiri oleh baris baru, bahkan baris terakhir.
kendaraan roda
116

The docs python merekomendasikan cara ini:

with open('file_to_write', 'w') as f:
    f.write('file contents\n')

Jadi begini biasanya saya melakukannya :)

Pernyataan dari docs.python.org :

Ini adalah praktik yang baik untuk menggunakan kata kunci 'with' ketika berhadapan dengan objek file. Ini memiliki keuntungan bahwa file ditutup dengan benar setelah suite-nya selesai, bahkan jika ada pengecualian yang muncul. Ini juga jauh lebih pendek daripada menulis blok coba-akhirnya yang setara.

j7nn7k
sumber
1
Saya tidak suka cara ini ketika saya perlu membuat sarang di withdalam lingkaran. Itu membuat saya terus membuka dan menutup file saat saya melanjutkan di loop saya. Mungkin saya kehilangan sesuatu di sini, atau ini benar-benar merugikan dalam skenario khusus ini?
Sibbs Gambling
38
Bagaimana dengan perulangan di dalam dengan?
j7nn7k
@ j7nn7k untuk baris dalam fd:
momstouch
86

Mengenai os.linesep:

Berikut ini adalah sesi juru bahasa Python 2.7.1 yang belum diedit pada Windows:

Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.linesep
'\r\n'
>>> f = open('myfile','w')
>>> f.write('hi there\n')
>>> f.write('hi there' + os.linesep) # same result as previous line ?????????
>>> f.close()
>>> open('myfile', 'rb').read()
'hi there\r\nhi there\r\r\n'
>>>

Di Windows:

Seperti yang diharapkan, os.linesep TIDAK menghasilkan hasil yang sama seperti '\n'. Tidak ada cara yang bisa menghasilkan hasil yang sama. 'hi there' + os.linesepsetara dengan 'hi there\r\n', yang TIDAK setara dengan 'hi there\n'.

Ini sederhana: penggunaan \nyang akan diterjemahkan secara otomatis ke os.linesep. Dan sudah semudah itu sejak port pertama Python ke Windows.

Tidak ada gunanya menggunakan os.linesep pada sistem non-Windows, dan itu menghasilkan hasil yang salah pada Windows.

JANGAN GUNAKAN os.linesep!

John Machin
sumber
contoh bagus - penasaran apakah Anda pengguna ipython? fungsi yang bagus untuk sesi pemformatan
Alvin
Saya tidak sepenuhnya yakin apa yang Anda coba sampaikan kepada kami di sini. os.linesep akan mengembalikan karakter istilah garis (atau string) seperti yang didefinisikan oleh sistem operasi. Windows menggunakan \ r \ n untuk akhiran baris secara default. Namun, satu \ n dikenali. Menggunakan \ n akan memberikan OUTPUT yang sepenuhnya portabel tetapi os.linesep tidak salah pada windows.
Gusdor
5
@ Goddor: Intinya adalah bahwa jika Anda secara eksplisit menggunakan os.linesepWindows dalam mode teks, hasilnya adalah \r\r\nyang salah. "Windows menggunakan ..." tidak ada artinya. Pustaka runtime C (dan karenanya Python) menerjemahkan \nke \r\npada output dalam mode teks. Perangkat lunak lain mungkin berperilaku berbeda. BUKAN semua perangkat lunak yang berjalan di Windows mengenali satu-satunya \nsebagai pemisah garis saat membaca dalam mode teks. Python melakukannya. Editor teks Notepad Microsoft tidak.
John Machin
6
Bisa dibilang orang lain akan membacanya, bukan Anda, dengan beberapa perangkat lunak mickey-mouse yang akan muntah tentang tambahan \r...
John Machin
2
@ Goddor Anda datang ke python dari bahasa yang berbeda, di mana menggunakan '\ n' menghasilkan output dari '\ n' di jendela, daripada '\ r \ n' - sehingga tidak memiliki '\ r' yang diharapkan oleh bodoh editor teks? Seperti yang dikatakan John, bukan itu perilaku Python - '\ n' secara otomatis diganti oleh '\ r \ n', jika itu yang dikatakan os.linesep lakukan. Oleh karena itu, mengatakan secara eksplisit os.linesep adalah "salah" di sini. Itu seperti Department of Redundancy Department. Ya kamu bisa melakukannya. Tidak, kamu tidak mau.
ToolmakerSteve
55

Saya tidak berpikir ada cara yang "benar".

Saya akan menggunakan:

with open ('myfile', 'a') as f: f.write ('hi there\n')

In Memoriam Tim Toady .

Hyperboreus
sumber
Tetapi OP mungkin ingin menulis hal-hal tambahan ke file. Di sini file akan ditutup ketika withkeluar dari ruang lingkup.
Keith
Itu mungkin ingin menjadi open(..., 'a')atau bahkan 'at'.
mtrw
5
Erm, yeah. Itulah ide menggunakan dengan. Jika Anda ingin menjaga file tetap terbuka, panggil saja buka di awal dan tutup ketika Anda selesai ...
Hyperboreus
1
@ mtrw. Benar. OP menambahkan.
Hyperboreus
1
Sejauh menyangkut python adalah RIP Tim Toady - dan sangat sangat sangat memang seharusnya
Mr_and_Mrs_D
21

Dalam Python 3 itu adalah fungsi, tetapi dalam Python 2 Anda dapat menambahkan ini ke bagian atas file sumber:

from __future__ import print_function

Lalu kamu lakukan

print("hi there", file=f)
Keith
sumber
17

Jika Anda menulis banyak data dan kecepatan adalah masalah yang mungkin harus Anda lakukan f.write(...). Saya melakukan perbandingan kecepatan cepat dan itu jauh lebih cepat daripada print(..., file=f)ketika melakukan banyak menulis.

import time    

start = start = time.time()
with open("test.txt", 'w') as f:
    for i in range(10000000):
        # print('This is a speed test', file=f)
        # f.write('This is a speed test\n')
end = time.time()
print(end - start)

Rata write- rata selesai dalam 2,45 detik pada mesin saya, sedangkan printwaktu sekitar 4 kali lebih lama (9,76 detik). Yang sedang berkata, dalam sebagian besar skenario dunia nyata ini tidak akan menjadi masalah.

Jika Anda memilih untuk pergi dengan print(..., file=f)Anda, Anda mungkin akan ingin menekan baris baru dari waktu ke waktu, atau menggantinya dengan yang lain. Ini dapat dilakukan dengan mengatur endparameter opsional , misalnya;

with open("test", 'w') as f:
    print('Foo1,', file=f, end='')
    print('Foo2,', file=f, end='')
    print('Foo3', file=f)

Apa pun cara yang Anda pilih, saya sarankan menggunakan withkarena membuat kode lebih mudah dibaca.

Pembaruan : Perbedaan dalam kinerja ini dijelaskan oleh fakta bahwa writesangat buffered dan kembali sebelum menulis ke disk benar-benar terjadi (lihat jawaban ini ), sedangkan print(mungkin) menggunakan buffering garis. Tes sederhana untuk ini adalah untuk memeriksa kinerja untuk penulisan yang lama juga, di mana kelemahan (dalam hal kecepatan) untuk buffering garis akan kurang jelas.

start = start = time.time()
long_line = 'This is a speed test' * 100
with open("test.txt", 'w') as f:
    for i in range(1000000):
        # print(long_line, file=f)
        # f.write(long_line + '\n')
end = time.time()

print(end - start, "s")

Perbedaan kinerja sekarang menjadi jauh lebih sedikit diucapkan, dengan waktu rata-rata 2,20 untuk writedan 3,10 untuk print. Jika Anda perlu menyatukan banyak string untuk mendapatkan kinerja garis loooong ini akan menderita, jadi kasus penggunaan di mana printakan lebih efisien agak jarang.

Robin Keskisarkka
sumber
10

Sejak 3,5 Anda juga dapat menggunakan pathlibuntuk tujuan itu:

Path.write_text(data, encoding=None, errors=None)

Buka file yang ditunjuk dalam mode teks, tulis data, dan tutup file:

import pathlib

pathlib.Path('textfile.txt').write_text('content')
Johnson
sumber
5

Ketika Anda mengatakan Baris, itu berarti beberapa karakter serial yang diakhiri dengan karakter '\ n'. Baris harus terakhir di beberapa titik jadi kita harus mempertimbangkan '\ n' di akhir setiap baris. Ini solusinya:

with open('YOURFILE.txt', 'a') as the_file:
    the_file.write("Hello")

dalam mode tambahkan setelah setiap tuliskan kursor pindah ke baris baru, jika Anda ingin menggunakan wmode Anda harus menambahkan \nkarakter di akhir write()fungsi:

the_file.write("Hello\n")
Reza Tanzifi
sumber
1
"dalam mode tambahkan setelah setiap tuliskan kursor pindah ke baris baru" - tidak.
An Se
3

Seseorang juga dapat menggunakan iomodul seperti pada:

import io
my_string = "hi there"

with io.open("output_file.txt", mode='w', encoding='utf-8') as f:
    f.write(my_string)
kmario23
sumber
1

Untuk menulis teks dalam file dalam termos dapat digunakan:

filehandle = open("text.txt", "w")
filebuffer = ["hi","welcome","yes yes welcome"]
filehandle.writelines(filebuffer)
filehandle.close()
Sashini Hettiarachchi
sumber
0

Anda juga bisa mencoba filewriter

pip install filewriter

from filewriter import Writer

Writer(filename='my_file', ext='txt') << ["row 1 hi there", "row 2"]

Menulis ke dalam my_file.txt

Mengambil iterable atau objek dengan __str__dukungan.

Emin Bugra Saral
sumber
0

Ketika saya harus menulis banyak baris baru, saya mendefinisikan lambda yang menggunakan printfungsi:

out = open(file_name, 'w')
fwl = lambda *x, **y: print(*x, **y, file=out) # FileWriteLine
fwl('Hi')

Pendekatan ini memiliki manfaat yaitu dapat memanfaatkan semua fitur yang tersedia dengan printfungsi tersebut.

Pembaruan: Seperti yang disebutkan oleh Georgy di bagian komentar, adalah mungkin untuk meningkatkan ide ini lebih jauh dengan partialfungsi:

from functools import partial
fwl = partial(print, file=out)

IMHO, ini adalah pendekatan yang lebih fungsional dan kurang samar.

MxNx
sumber
2
Atau yang lain (mungkin lebih bersih) cara untuk menulis ini: from functools import partial; fwl = partial(print, file=out).
Georgy
@ Georgy Pendekatan Anda sangat baik sehingga dapat diberikan sebagai jawaban baru.
MxNx
1
Idenya sama dengan milik Anda, hanya implementasi yang sedikit berbeda. Jika mau, Anda bisa menambahkannya di edit untuk jawaban Anda. Saya baik-baik saja dengan itu.
Georgy