Cách chính xác để viết dòng vào tập tin?


1069

Tôi đã từng làm print >>f, "hi there"

Tuy nhiên, dường như điều đó print >>đang bị phản đối. Cách được đề xuất để làm dòng trên là gì?

Cập nhật : Liên quan đến tất cả những câu trả lời với "\n"... đây là phổ quát hay Unix cụ thể? IE, tôi có nên làm "\r\n"trên Windows không?


11
"\ n" không dành riêng cho Unix. Khi tệp được mở ở chế độ văn bản (mặc định), nó sẽ được dịch tự động sang đúng dòng kết thúc cho nền tảng hiện tại. Viết "\ r \ n" sẽ tạo ra "\ r \ r \ n" sai.
D Coetzee

Chỉ cần thêm câu lệnh in (os.linesep) để xem mã ascii (10 trên hầu hết các hệ thống UNIX)
Stefan Gruenwald

Tại sao bạn nghĩ rằng nó bị phản đối?
xxx ---

Câu trả lời:


1153

Điều này nên đơn giản như:

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

Từ Tài liệu:

Không sử dụng os.lineseplàm dấu kết thúc dòng khi ghi tệp được mở ở chế độ văn bản (mặc định); thay vào đó, hãy sử dụng một '\ n' trên tất cả các nền tảng.

Một số cách đọc hữu ích:


37
Ví dụ này tốt hơn ví dụ mở / đóng. Sử dụng withlà một cách an toàn hơn để nhớ để đóng một tập tin.
Mắt

18
Tôi không phải gọi the_file.close()?
Hussain


@Johnsyweb Tại sao bạn nói "os.linesep. Có rất nhiều thứ hay ho trong os!", Khi bạn trước đó trong bài viết đề nghị không sử dụng nó? Tôi nghi ngờ một chỉnh sửa ở đây, và nó có thể là lý do cho số phiếu giảm.
Ngựa SMith

1
@ user3226167: Đó là một điểm thú vị. Nhưng tại sao bạn lại mở một tệp nhị phân để viết văn bản đơn giản?
Johnsyweb

961

Bạn nên sử dụng print()hàm có sẵn từ Python 2.6+

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

Đối với Python 3, bạn không cần import, vì print()hàm này là mặc định.

Thay thế sẽ là sử dụng:

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

Trích dẫn từ tài liệu Python liên quan đến dòng mới:

Trên đầu ra, nếu dòng mới là Không có, bất kỳ '\n'ký tự nào được viết sẽ được dịch sang dấu phân cách dòng mặc định của hệ thống , os.linesep. Nếu dòng mới là '', không có bản dịch diễn ra. Nếu dòng mới là bất kỳ giá trị pháp lý nào khác, bất kỳ '\n'ký tự nào được viết sẽ được dịch sang chuỗi đã cho.


35
-1 "Nếu bạn muốn chắc chắn, hãy thêm os.linesep vào chuỗi thay vì \n" sẽ yêu cầu newline = "" nếu không bạn sẽ nhận được \r\r\ntrên Windows. Không có lý do gì để futz về với os.linesep cả.
John Machin

7
@Sorin: Chỉnh sửa của bạn để thêm chế độ ghi tất nhiên là một sự cải tiến. Tuy nhiên, bạn vẫn lạ lùng về os.linesep. Xem câu trả lời của tôi. Nhân tiện, tài liệu mà bạn trích dẫn là 3.x, nhưng phần này cũng hợp lệ cho 2.x ở chế độ văn bản: mọi ký tự '\ n' được viết đều được dịch sang dấu tách dòng mặc định của hệ thống, os.linesep * . .. Windows: viết os.linesep giống như viết \r\ncó chứa \ndịch sang os.linesep, \r\nkết quả cuối cùng là như vậy \r\r\n.
John Machin

7
@ John bạn đã đúng, tôi đã sửa lỗi os.linesep. Cảm ơn.
sorin

3
Để nối thêm không phải là nó open('myfile','a')thay thế open('myfile','w')?
NeDark

6
@BradRuderman Đó là một phần của tiêu chuẩn POSIX cho những gì tạo thành một "dòng" trong tệp văn bản, tức là mọi dòng trong tệp văn bản phải được chấm dứt bởi một dòng mới, thậm chí là dòng cuối cùng.
bánh xe

116

Các tài liệu python đề nghị theo cách này:

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

Vì vậy, đây là cách tôi thường làm :)

Tuyên bố từ docs.python.org :

Đó là một thực hành tốt để sử dụng từ khóa 'với' khi xử lý các đối tượng tệp. Điều này có lợi thế là tập tin được đóng đúng cách sau khi bộ của nó kết thúc, ngay cả khi một ngoại lệ được đưa ra trên đường đi. Nó cũng ngắn hơn nhiều so với việc viết các khối thử cuối cùng tương đương.


1
Tôi không thích cách này khi tôi cần lồng withvào vòng lặp. Điều đó khiến tôi liên tục mở và đóng tệp khi tôi tiến hành trong vòng lặp của mình. Có lẽ tôi đang thiếu một cái gì đó ở đây, hoặc đây thực sự là một bất lợi trong kịch bản cụ thể này?
Đánh bạc Sibbs

38
Làm thế nào về vòng lặp trong với?
j7nn7k

@ j7nn7k cho dòng trong fd:
momstouch

86

Về os.linesep:

Dưới đây là phiên phiên dịch Python 2.7.1 chưa được chỉnh sửa chính xác trên 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'
>>>

Trên Windows:

Như mong đợi, os.linesep KHÔNG tạo ra kết quả tương tự như '\n'. Không có cách nào nó có thể tạo ra kết quả tương tự. 'hi there' + os.lineseptương đương với 'hi there\r\n', mà KHÔNG tương đương với 'hi there\n'.

Thật đơn giản: sử dụng \nsẽ được dịch tự động sang os.linesep. Và nó thật đơn giản kể từ lần đầu tiên chuyển Python sang Windows.

Không có điểm nào trong việc sử dụng os.linesep trên các hệ thống không phải Windows và nó tạo ra kết quả sai trên Windows.

KHÔNG SỬ DỤNG os.linesep!


ví dụ tuyệt vời - tò mò nếu bạn là người dùng ipython? các chức năng hay để định dạng phiên
Alvin

Tôi không hoàn toàn chắc chắn những gì bạn đang cố nói với chúng tôi ở đây. os.linesep sẽ trả về ký tự dòng (hoặc chuỗi) theo định nghĩa của hệ điều hành. Windows sử dụng \ r \ n cho các kết thúc dòng theo mặc định. Tuy nhiên, một \ n được công nhận. Sử dụng \ n sẽ mang lại một OUTPUT hoàn toàn di động nhưng os.linesep không sai trên windows.
Gusdor

5
@Gusdor: Vấn đề là nếu bạn sử dụng rõ ràng os.lineseptrong Windows ở chế độ văn bản, kết quả \r\r\nlà sai. "Windows sử dụng ..." là vô nghĩa. Thư viện thời gian chạy C (và do đó Python) dịch \nsang \r\nđầu ra ở chế độ văn bản. Phần mềm khác có thể hành xử khác nhau. Đây không phải là trường hợp mà tất cả các phần mềm chạy trên Windows đều nhận ra một \ndấu phân tách đơn độc khi đọc ở chế độ văn bản. Python nào. Trình soạn thảo văn bản Notepad của Microsoft không.
John Machin

6
Có thể cho rằng ai đó sẽ đọc nó, không phải bạn, với một số phần mềm mickey-mouse sẽ giới thiệu thêm \r...
John Machin

2
@Gusdor là bạn đến với python từ một ngôn ngữ khác, trong đó sử dụng '\ n' dẫn đến kết quả đầu ra của '\ n' trên cửa sổ, thay vì '\ r \ n' - vì vậy nó thiếu '\ r' do câm biên tập văn bản? Như John nói, đó không phải là cách Python hành xử - '\ n' được tự động thay thế bằng '\ r \ n', nếu đó là điều os.linesep nói phải làm. Do đó, nói rõ ràng os.linesep "sai" ở đây. Nó như thế Department of Redundancy Department. Có, bạn có thể làm điều đó. Không, bạn không muốn.
ToolmakerSteve 19/12/13

55

Tôi không nghĩ có một cách "chính xác".

Tôi sẽ dùng:

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

Trong bản ghi nhớ Tim Toady .


Nhưng OP có thể muốn ghi thêm nội dung vào tệp. Ở đây các tập tin sẽ được đóng lại khi withđi ra khỏi phạm vi.
Keith

Điều đó có thể muốn open(..., 'a')hoặc thậm chí 'at'.
mtrw

5
Ơ, ừ. Đó là ý tưởng của việc sử dụng với. Nếu bạn muốn giữ tệp mở, chỉ cần gọi mở ở đầu và gọi đóng khi bạn hoàn tất ...
Hyperboreus

1
@mtrw. Thật. OP đã được bổ sung.
Hyperboreus

1
Theo như python có liên quan là RIP Tim Toady - và rất rất rất đúng
Mr_and_Mrs_D

21

Trong Python 3, nó là một hàm, nhưng trong Python 2, bạn có thể thêm phần này vào đầu tệp nguồn:

from __future__ import print_function

Sau đó bạn làm

print("hi there", file=f)

17

Nếu bạn đang viết nhiều dữ liệu và tốc độ là mối quan tâm bạn có lẽ nên đi cùng f.write(...). Tôi đã làm một so sánh tốc độ nhanh và nó nhanh hơn đáng kể so với print(..., file=f)khi thực hiện một số lượng lớn các bài viết.

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)

Trung bình writehoàn thành trong 2,45 giây trên máy của tôi, trong khiprint mất khoảng 4 lần thời gian (9,76 giây). Điều đó đang được nói, trong hầu hết các kịch bản trong thế giới thực, điều này sẽ không thành vấn đề.

Nếu bạn chọn đi cùng, có thể print(..., file=f)bạn sẽ thấy rằng thỉnh thoảng bạn sẽ muốn chặn dòng mới hoặc thay thế nó bằng một thứ khác. Điều này có thể được thực hiện bằng cách đặt endtham số tùy chọn , ví dụ;

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

Dù bạn chọn cách nào tôi cũng khuyên bạn nên sử dụng withvì nó giúp mã dễ đọc hơn nhiều.

Cập nhật : Sự khác biệt về hiệu suất này được giải thích bởi thực tế writelà bộ đệm cao và trả về trước khi bất kỳ ghi vào đĩa thực sự diễn ra (xem câu trả lời này ), trong khi print(có thể) sử dụng bộ đệm dòng. Một thử nghiệm đơn giản cho điều này sẽ là kiểm tra hiệu năng cho việc viết dài, trong đó những nhược điểm (về tốc độ) đối với bộ đệm dòng sẽ ít rõ ràng hơn.

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")

Sự khác biệt hiệu suất bây giờ trở nên ít rõ rệt hơn, với thời gian trung bình là 2,20 giây writevà 3,10 giây cho print. Nếu bạn cần nối một chuỗi các chuỗi để có hiệu suất dòng loooong này sẽ bị ảnh hưởng, vì vậy các trường hợp sử dụng printsẽ hiệu quả hơn là hơi hiếm.


10

Từ 3,5 bạn cũng có thể sử dụng pathlibcho mục đích đó:

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

Mở tệp được trỏ đến trong chế độ văn bản, ghi dữ liệu vào tệp và đóng tệp:

import pathlib

pathlib.Path('textfile.txt').write_text('content')

5

Khi bạn nói Line, nó có nghĩa là một số ký tự được nối tiếp được kết thúc thành các ký tự '\ n'. Dòng nên ở cuối tại một số điểm vì vậy chúng tôi nên xem xét '\ n' ở cuối mỗi dòng. Đây là giải pháp:

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

trong chế độ chắp thêm sau mỗi lần ghi, con trỏ di chuyển sang dòng mới, nếu bạn muốn sử dụng wchế độ, bạn nên thêm các \nký tự ở cuối write()chức năng:

the_file.write("Hello\n")

1
"trong chế độ chắp thêm sau mỗi lần ghi, con trỏ di chuyển sang dòng mới" - không, không phải vậy.
An Se

3

Người ta cũng có thể sử dụng iomô-đun như trong:

import io
my_string = "hi there"

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

1

Để viết văn bản trong một tập tin trong bình có thể được sử dụng:

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

0

Bạn cũng có thể thử filewriter

pip install filewriter

from filewriter import Writer

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

Viết vào my_file.txt

Đưa một iterable hoặc một đối tượng có __str__hỗ trợ.


0

Khi tôi cần viết nhiều dòng mới, tôi xác định lambda sử dụng printhàm:

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

Cách tiếp cận này có lợi ích là nó có thể sử dụng tất cả các tính năng có sẵn với printchức năng.

Cập nhật: Như được đề cập bởi Georgy trong phần bình luận, có thể cải thiện ý tưởng này hơn nữa với partialchức năng:

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

IMHO, đây là một cách tiếp cận nhiều chức năng hơn và ít khó hiểu hơn.


2
Hoặc một cách khác (có thể sạch hơn) để viết này : from functools import partial; fwl = partial(print, file=out).
Georgy

@Georgy Cách tiếp cận của bạn tốt đến mức nó có thể được đưa ra như một câu trả lời mới.
MxNx

1
Ý tưởng giống như của bạn, chỉ cần thực hiện là một chút khác nhau. Nếu bạn muốn, bạn có thể thêm nó vào một chỉnh sửa cho câu trả lời của bạn. Tôi ổn với nó
Georgy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.