Правильный способ записи строки в файл?

1070

Я привык делать print >>f, "hi there"

Тем не менее, кажется, что print >>становится устаревшим. Каков рекомендуемый способ сделать строку выше?

Обновление : Относительно всех этих ответов "\n"... это универсально или специфично для Unix? IE, я должен делать "\r\n"на Windows?

Ярослав Булатов
источник
11
«\ n» не зависит от Unix. Когда файл открывается в текстовом режиме (по умолчанию), он автоматически переводится в правильное окончание строки для текущей платформы. Запись "\ r \ n" приведет к "\ r \ r \ n", что неправильно.
D Coetzee
Просто добавьте оператор print ord (os.linesep), чтобы увидеть код ascii (10 в большинстве систем UNIX)
Стефан Грюнвальд,
Как вы думаете, почему это устарело?
---

Ответы:

1155

Это должно быть так просто, как:

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

Из документации:

Не используйте os.linesepв качестве ограничителя строки при записи файлов, открытых в текстовом режиме (по умолчанию); вместо этого используйте один '\ n' на всех платформах.

Некоторое полезное чтение:

Johnsyweb
источник
37
Этот пример лучше, чем пример открытия / закрытия. Использование with- это более безопасный способ забыть закрыть файл.
Eyal
18
Мне не нужно звонить the_file.close()?
Хуссейн
19
нет, не надо: stackoverflow.com/questions/3012488/…
Тэл Джером
@Johnsyweb Почему вы говорите «os.linesep. В OS много хорошего!», Когда вы ранее в посте рекомендовали не использовать его? Я подозреваю, что редактирование здесь, и это может быть причиной для отрицательных голосов.
Лошадь SMith
1
@ user3226167: Это интересный момент. Но зачем открывать бинарный файл для записи простого текста?
Johnsyweb
961

Вы должны использовать print()функцию, которая доступна с Python 2.6+

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

Для Python 3 вам не нужно import, так как print()функция по умолчанию.

Альтернативой было бы использовать:

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

Цитирование из документации Python относительно новых строк:

На выходе, если новая строка не является None, любые '\n'символы , написанные переведены в сепаратор линии системы по умолчанию, os.linesep. Если ''перевод строки - перевод не выполняется. Если '\n'символ новой строки является любым из других допустимых значений, любые написанные символы переводятся в данную строку.

Сорин
источник
35
-1 "Если вы хотите быть уверенным, добавьте os.linesep в строку вместо \n" Требуется newline = "", иначе вы получите \r\r\nWindows. Нет никаких причин возиться с os.linesep вообще.
Джон Мачин
7
@ Сорин: Ваше редактирование, чтобы добавить режим записи, конечно, улучшение. Однако вы странным образом остаетесь непримиримым в отношении os.linesep. Смотри мой ответ. Кстати, документация, которую вы цитируете, относится к 3.x, но эта часть также действительна для 2.x в текстовом режиме: любые написанные символы '\ n' транслируются в системный разделитель строк по умолчанию, os.linesep * . .. Windows: запись os.linesep - это то же самое, что запись, \r\nкоторая содержит \nперевод в os.linesep, то есть \r\nконечный результат \r\r\n.
Джон Мачин
7
@ Джон, ты был прав, я исправил ошибку os.linesep. Спасибо.
Сорин
3
Для добавления не правда ли open('myfile','a')вместо open('myfile','w')?
NeDark
6
@BradRuderman Это часть стандарта POSIX для того, что представляет собой «строку» в текстовом файле, то есть каждая строка в текстовом файле должна заканчиваться новой строкой, даже последней строкой.
Уилер
116

Документы Python рекомендуют так:

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

Так я обычно так и делаю :)

Заявление от docs.python.org :

Это хорошая практика , чтобы использовать «с» ключевым словом при работе с файловыми объектами. Преимущество заключается в том, что файл правильно закрывается после завершения его набора, даже если по пути возникает исключение. Это также намного короче, чем написание эквивалентных блоков try-finally.

j7nn7k
источник
1
Мне не нравится этот способ, когда мне нужно вложить в withцикл. Это заставляет меня постоянно открывать и закрывать файл, пока я продолжаю цикл. Может быть, я что-то здесь упускаю, или это действительно недостаток в этом конкретном сценарии?
Sibbs Gambling
38
Как насчет цикла внутри с?
j7nn7k
@ j7nn7k для строки в fd:
momstouch
86

Относительно os.linesep:

Вот точный неотредактированный сеанс интерпретатора Python 2.7.1 в 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'
>>>

В Windows:

Как и ожидалось, os.linesep НЕ дает того же результата, что и '\n'. Нет никакого способа, чтобы это могло привести к тому же самому результату. 'hi there' + os.linesepэквивалентно 'hi there\r\n', что не эквивалентно 'hi there\n'.

Это так просто: используйте, \nкоторый будет автоматически переведен на os.linesep. И это было так просто с первого порта Python для Windows.

Нет смысла использовать os.linesep в системах, отличных от Windows, и это приводит к неверным результатам в Windows.

НЕ ИСПОЛЬЗУЙТЕ os.linesep!

Джон Мачин
источник
отличный пример - интересно, если вы являетесь пользователем ipython? хорошие функции для форматирования сессий
Элвин
Я не совсем уверен, что вы пытаетесь сказать нам здесь. os.linesep вернет символ строки (или строку), как это определено операционной системой. Windows использует \ r \ n для окончания строки по умолчанию. Тем не менее, один \ n распознается. Использование \ n даст полностью переносимый OUTPUT, но os.linesep не ошибается в Windows.
Гусдор
5
@Gusdor: Дело в том, что если вы явно используете os.linesepWindows в текстовом режиме, результат \r\r\nбудет неправильным. «Windows использует ...» не имеет смысла. Библиотека C во время выполнения (и , следовательно , Python) перевести \nна \r\nна выходе в текстовом режиме. Другое программное обеспечение может вести себя по-другому. Это НЕ тот случай, когда все программное обеспечение, работающее в Windows, распознает одинокий \nкак разделитель строк при чтении в текстовом режиме. Python делает. Текстовый редактор Microsoft Notepad этого не делает.
Джон Мачин
6
Возможно, кто-то другой будет читать это, а не вы, с каким-нибудь программным обеспечением для микки-мауса, которое будет раздражать насчет дополнительного \r...
Джон Мачин
2
@Gusdor - вы переходите на python с другого языка, где использование '\ n' приводит к выводу '\ n' в окне, а не '\ r \ n' - поэтому ему не хватает '\ r', ожидаемого тупым текстовые редакторы? Как говорит Джон, это не так, как ведет себя Python - «\ n» автоматически заменяется на «\ r \ n», если это то, что говорит os.linesep. Следовательно, явное изречение os.linesep здесь "неправильно". Это как Department of Redundancy Department. Да, ты можешь сделать это. Нет, ты не хочешь.
ToolmakerSteve
55

Я не думаю, что есть «правильный» путь.

Я хотел бы использовать:

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

Памяти Тима Тоади .

Hyperboreus
источник
Но ОП может захотеть записать дополнительные вещи в файл. Здесь файл будет закрыт, когда withвыходит за рамки.
Кит
Это может быть, open(..., 'a')или даже 'at'.
mtrw
5
Хм, да. Это идея использования с. Если вы хотите, чтобы файл оставался открытым, просто позвоните открыть в начале и закройте, когда закончите ...
Гиперборей
1
@mtrw. Правда. ОП добавлялся.
Гиперборей
1
Что касается питона, то RIP Тим Тоади - и очень, очень и очень справедливо
Mr_and_Mrs_D
21

В Python 3 это функция, но в Python 2 вы можете добавить это в начало исходного файла:

from __future__ import print_function

Тогда вы делаете

print("hi there", file=f)
Кит
источник
17

Если вы пишете много данных, и скорость - это проблема, с которой вам, вероятно, стоит пойти f.write(...). Я сделал быстрое сравнение скорости, и это было значительно быстрее, чем print(..., file=f)при выполнении большого количества записей.

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)

В среднем writeфинишировал за 2,45 секунды на моей машине, а printзанял в 4 раза больше времени (9,76 секунды). При этом в большинстве реальных сценариев это не будет проблемой.

Если вы решите пойти с print(..., file=f)вами, вы, вероятно, обнаружите, что хотите время от времени подавлять новую строку или заменять ее чем-то другим. Это можно сделать, установив необязательный endпараметр, например;

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

Какой бы способ вы ни выбрали, я бы посоветовал использовать withего, поскольку он значительно облегчает чтение кода.

Обновление : это различие в производительности объясняется тем фактом, что он writeимеет высокую буферизацию и возвращается до того, как произойдет какая-либо запись на диск (см. Этот ответ ), тогда как print(вероятно) используется буферизация строки. Простым тестом для этого будет проверка производительности и для длинных записей, где недостатки (с точки зрения скорости) для буферизации строк будут менее выраженными.

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

Разница в производительности теперь становится гораздо менее выраженной, со средним временем 2,20 с writeи 3,10 с print. Если вам нужно объединить кучу строк, чтобы получить эту длинную строку, производительность пострадает, поэтому случаи, где printбы эффективность была более эффективной, встречаются немного редко.

Робин Кескисаркка
источник
10

Начиная с 3.5 вы также можете использовать pathlibдля этой цели:

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

Откройте указанный файл в текстовом режиме, запишите в него данные и закройте файл:

import pathlib

pathlib.Path('textfile.txt').write_text('content')
Джонсон
источник
5

Когда вы говорите «Линия», это означает некоторые сериализованные символы, которые заканчиваются на символы «\ n». Строка должна быть последней в некоторой точке, поэтому мы должны рассмотреть '\ n' в конце каждой строки. Вот решение:

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

в режиме добавления после каждой записи курсор перемещается на новую строку, если вы хотите использовать wрежим, вы должны добавить \nсимволы в конце write()функции:

the_file.write("Hello\n")
Реза Танзифи
источник
1
«в режиме добавления после каждой записи курсор перемещается на новую строку» - нет, это не так.
СЭ
3

Можно также использовать ioмодуль как в:

import io
my_string = "hi there"

with io.open("output_file.txt", mode='w', encoding='utf-8') as f:
    f.write(my_string)
kmario23
источник
1

Для записи текста в файл в колбу можно использовать:

filehandle = open("text.txt", "w")
filebuffer = ["hi","welcome","yes yes welcome"]
filehandle.writelines(filebuffer)
filehandle.close()
Сашини Хеттиараччи
источник
0

Вы также можете попробовать filewriter

pip install filewriter

from filewriter import Writer

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

Пишет в my_file.txt

Принимает итерируемый или объект с __str__поддержкой.

Эмин Бугра Сарал
источник
0

Когда мне нужно много писать новые строки, я определяю лямбду, которая использует printфункцию:

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

Преимущество этого подхода состоит в том, что он может использовать все функции, доступные в данной printфункции.

Обновление: как упомянул Георгий в разделе комментариев, можно улучшить эту идею с помощью partialфункции:

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

ИМХО, это более функциональный и менее загадочный подход.

MxNx
источник
2
Или другой (возможно , уборщик) способ написать это: from functools import partial; fwl = partial(print, file=out).
Георгий
@ Георгий Ваш подход настолько хорош, что его можно дать в качестве нового ответа.
MxNx
1
Идея такая же, как у вас, просто реализация немного другая. Если вы хотите, вы можете добавить его в редактировании своего ответа. Я в порядке с этим.
Георгий