Правильний спосіб записати рядок у файл?


1069

Я звик робити 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)
Стефан Груенвальд

Чому, на вашу думку, це застаріло?
xxx ---

Відповіді:


1152

Це повинно бути таким же простим, як:

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

З документації:

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

Деякі корисні читання:

  • withзаяву
  • open()
    • 'a' призначений для додавання або використання
    • 'w' писати зі скороченням
  • os(зокрема os.linesep)

36
Цей приклад кращий, ніж приклад відкритого / закритого. Використання with- це більш безпечний спосіб запам'ятати закриття файлу.
Eyal

18
Мені не потрібно дзвонити the_file.close()?
Хуссейн


@Johnsyweb Чому ви говорите "os.linesep. Є багато хороших речей в os!", Коли ви раніше в посту рекомендували проти його використання? Я підозрюю редагування тут, і це може бути причиною зниження голосів.
Кінь Сміт

1
@ user3226167: Це цікавий момент. Але чому б ви відкрили двійковий файл, щоб написати звичайний текст?
Джонсонвев

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\nв Windows. Немає жодних підстав для того, щоб хотіти з os.linesep.
Джон Махін

7
@Sorin: Ваш режим редагування, щоб додати режим запису, звичайно, вдосконалення. Однак ви дивно залишаєтесь непримітними щодо os.linesep. Дивіться мою відповідь. До речі, документація, яку ви цитуєте, стосується 3.x, але ця частина також дійсна для 2.x у текстовому режимі: будь-які записані символи '\ n' перекладаються на системний роздільник рядків за замовчуванням, os.linesep * . .. Windows: написання os.linesep - це те саме, що написання, \r\nяке містить, \nщо перекладається на os.linesep, тобто \r\nтаким є кінцевий результат \r\r\n.
Джон Махін

7
@John ви мали рацію, я виправив помилку os.linesep. Дякую.
sorin

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 :

Добре застосовувати ключове слово "з" при роботі з файловими об'єктами. Це має перевагу в тому, що файл належним чином закривається після закінчення його набору, навіть якщо в цьому випадку висунуто виняток. Це також набагато коротше, ніж писати еквівалентні блоки спробувати.


1
Мені це не подобається, коли мені потрібно вкласти withвсередині петлі. Це змушує мене постійно відкривати і закривати файл, коли я продовжую свою роботу. Можливо, я щось тут пропускаю, або це справді недолік у цьому конкретному сценарії?
Сіббс Азартні ігри

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.linesepв Windows у текстовому режимі, результат \r\r\nє неправильним. "Windows використовує ..." безглуздо. Бібліотека C під час виконання (і , отже , Python) перевести \nна \r\nна виході в текстовому режимі. Інше програмне забезпечення може поводитися інакше. НЕ так, що все програмне забезпечення, яке працює на Windows, розпізнає одиноку \nяк роздільник рядків під час читання в текстовому режимі. Пітон робить. Текстовий редактор "Блокнот" Microsoft не працює.
Джон Махін

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

На згадку про Тіма Тоді .


Але ОП може захотіти написати додатковий матеріал у файл. Тут файл буде закритий, коли він withвийде за межі області.
Кіт

Це може хотіти бути open(..., 'a')чи навіть 'at'.
mtrw

5
Ем, так. Це ідея використання з. Якщо ви хочете зберегти файл відкритим, просто зателефонуйте відкритим на початку та зателефонуйте закрити, коли ви закінчите ...
Гіперборей

1
@mtrw. Правда. ОП додавали.
Гіперборей

1
Що стосується python, це 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)

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)

ІМХО, це більш функціональний і менш критичний підхід.


2
Або інший (можливо , прибиральник) спосіб написати це: from functools import partial; fwl = partial(print, file=out).
Георгій

@Georgy Ваш підхід настільки гарний, що його можна дати як нову відповідь.
MxNx

1
Ідея така ж, як і у вас, просто реалізація трохи інша. Якщо ви хочете, ви можете додати його у редагуванні до своєї відповіді. Я з цим добре.
Георгій
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.