Maneira correta de escrever linha para arquivo?


1069

Estou acostumado a fazer print >>f, "hi there"

No entanto, parece que print >>está sendo preterido. Qual é a maneira recomendada de fazer a linha acima?

Atualização : Em relação a todas essas respostas com "\n"... isso é universal ou específico para Unix? IE, devo fazer "\r\n"no Windows?


11
"\ n" não é específico do Unix. Quando o arquivo é aberto no modo de texto (o padrão), ele é convertido automaticamente para a linha correta que termina na plataforma atual. Escrever "\ r \ n" produziria "\ r \ r \ n" errado.
D # Coetzee #

Basta adicionar a declaração ord print (os.linesep) para ver o código ascii (10 na maioria dos sistemas UNIX)
Stefan Gruenwald

Por que você acha que foi preterido?
xxx ---

Respostas:


1153

Isso deve ser tão simples quanto:

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

Da documentação:

Não use os.linesepcomo terminador de linha ao gravar arquivos abertos no modo de texto (o padrão); use um único '\ n' em todas as plataformas.

Alguma leitura útil:


37
Este exemplo é melhor que o exemplo de abrir / fechar. Usar withé uma maneira mais segura de lembrar de fechar um arquivo.
Eyal

18
Eu não tenho que ligar the_file.close()?
precisa


@Johnsyweb Por que você diz "os.linesep. Há muitas coisas boas no SO!", Quando você recomendou anteriormente no início do post que não usasse? Suspeito de uma edição aqui, e pode ser o motivo dos votos negativos.
Horse SMith

1
@ user3226167: Esse é um ponto interessante. Mas por que você abriria um arquivo binário para escrever texto sem formatação?
Johnsyweb 31/05

961

Você deve usar a print()função que está disponível desde o Python 2.6+

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

Para o Python 3, você não precisa do import, pois a print()função é o padrão.

A alternativa seria usar:

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

Citando a documentação do Python sobre novas linhas:

Na saída, se newline for None, qualquer '\n'caractere gravado será convertido no separador de linhas padrão do sistema os.linesep. Se for nova linha '', nenhuma tradução ocorrerá. Se nova linha for um dos outros valores legais, qualquer '\n'caractere gravado será convertido para a sequência especificada.


35
-1 "Se você quiser ter certeza, adicione os.linesep à string em vez de \n" exigiria newline = "" caso contrário, você acessará o \r\r\nWindows. Não há razão para brincar com o os.linesep.
John Machin 28/05

7
@ Sorin: Sua edição para adicionar o modo de gravação é obviamente uma melhoria. No entanto, você permanece estranhamente intransigente sobre o os.linesep. Veja minha resposta. A propósito, a documentação que você cita é para 3.x, mas esta parte também é válida para 2.x no modo de texto: qualquer caractere '\ n' escrito é convertido no separador de linha padrão do sistema, os.linesep * . .. Windows: escrever os.linesep é o mesmo que escrever \r\nque contém o \nque é traduzido para os.linesep, o que significa que \r\no resultado final é \r\r\n.
John Machin 29/05

7
@ John você estava certo, eu corrigi o bug os.linesep. Obrigado.
sorin 29/05

3
Para acrescentar não é ele open('myfile','a'), em vez open('myfile','w')?
NeDark

6
@BradRuderman Isso faz parte do padrão POSIX para o que constitui uma "linha" em um arquivo de texto, ou seja, cada linha em um arquivo de texto deve ser finalizada por uma nova linha, até a última linha.
veículo com rodas

116

Os documentos python recomendam desta maneira:

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

Então é assim que eu costumo fazer :)

Declaração de docs.python.org :

É uma boa prática usar a palavra-chave 'with' ao lidar com objetos de arquivo. Isso tem a vantagem de o arquivo ser fechado corretamente após a conclusão do conjunto, mesmo que uma exceção seja levantada no caminho. Também é muito mais curto que escrever blocos equivalentes de tentativa e finalmente.


1
Não gosto dessa maneira quando preciso aninhar o withinterior de um loop. Isso me faz constantemente abrir e fechar o arquivo à medida que prossigo no meu loop. Talvez esteja faltando alguma coisa aqui, ou isso é realmente uma desvantagem nesse cenário específico?
Sibbs Gambling

38
Que tal fazer um loop dentro do with?
J7nn7k

@ j7nn7k para linha em fd:
momstouch 19/06/19

86

Em relação ao os.linesep:

Aqui está uma sessão exata do intérprete não editada do Python 2.7.1 no 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'
>>>

No Windows:

Como esperado, o os.linesep NÃO produz o mesmo resultado que '\n'. Não há como produzir o mesmo resultado. 'hi there' + os.linesepé equivalente a 'hi there\r\n', que NÃO é equivalente a 'hi there\n'.

É simples: o uso \nserá traduzido automaticamente para os.linesep. E tem sido tão simples desde a primeira porta do Python para o Windows.

Não faz sentido usar o os.linesep em sistemas não Windows e produz resultados incorretos no Windows.

NÃO USE os.linesep!


ótimo exemplo - curioso se você é um usuário ipython? agradáveis funções de formatação de sessões
Alvin

Não tenho muita certeza do que você está tentando nos dizer aqui. o os.linesep retornará o caractere de termo de linha (ou string) conforme definido pelo sistema operacional. O Windows usa \ r \ n para fins de linha por padrão. No entanto, um único \ n é reconhecido. Usar \ n dará uma SAÍDA totalmente portátil, mas o os.linesep não está errado no Windows.
Gusdor

5
@ Gusdor: O ponto é que, se você usar explicitamente os.linesepno Windows no modo de texto, o resultado \r\r\nestá errado. "O Windows usa ..." não tem sentido. A biblioteca C tempo de execução (e, portanto, Python) traduzir \npara \r\na saída em modo texto. Outro software pode se comportar de maneira diferente. NÃO é o caso de todos os softwares em execução no Windows reconhecerem um solitário \ncomo um separador de linhas ao ler no modo de texto. Python faz. O editor de texto do bloco de notas da Microsoft não.
precisa

6
Indiscutivelmente alguém vai ler isso, não você, com algum software de mickey-mouse que vai vomitar sobre o extra de \r...
John Machin

2
@Gusdor você está chegando ao python de uma linguagem diferente, onde o uso de '\ n' resulta na saída de '\ n' na janela, em vez de '\ r \ n' - portanto, falta o '\ r' esperado por dumb editores de texto? Como John diz, não é assim que o Python se comporta - '\ n' é automaticamente substituído por '\ r \ n', se é isso que os.linesep diz para fazer. Portanto, dizer explicitamente os.linesep é "errado" aqui. É como Department of Redundancy Department. Sim, você pode fazer isso. Não, você não quer.
usar o seguinte

55

Eu não acho que exista uma maneira "correta".

Eu usaria:

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

Em memória de Tim Toady .


Mas o OP pode querer escrever coisas adicionais no arquivo. Aqui o arquivo será fechado quando withsair do escopo.
Keith

Isso pode querer ser open(..., 'a')ou até 'at'.
Mtrw 28/05

5
Erm, sim. Essa é a ideia de usar com. Se você quiser manter o arquivo aberto, basta ligar aberto no início e triz quando você está feito ...
Hyperboreus

1
@mtrw. Verdade. OP foi anexado.
Hyperboreus 28/05

1
Tanto quanto python está em causa é RIP Tim Toady - e muito, muito muito justamente por isso
Mr_and_Mrs_D

21

No Python 3, é uma função, mas no Python 2 você pode adicioná-lo à parte superior do arquivo de origem:

from __future__ import print_function

Então você faz

print("hi there", file=f)

17

Se você está escrevendo muitos dados e a velocidade é uma preocupação, provavelmente você deve concordar f.write(...). Fiz uma comparação rápida de velocidade e foi consideravelmente mais rápida do que print(..., file=f)na execução de um grande número de gravações.

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)

Em média, writeterminei em 2,45s na minha máquina, enquanto printdemorou cerca de 4 vezes mais (9,76s). Dito isto, na maioria dos cenários do mundo real, isso não será um problema.

Se você optar por acompanhá- print(..., file=f)lo, provavelmente descobrirá que deseja suprimir a nova linha de tempos em tempos ou substituí-la por outra. Isso pode ser feito configurando o endparâmetro opcional , por exemplo;

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

Qualquer que seja a maneira que você escolher, sugiro usar, withpois torna o código muito mais fácil de ler.

Atualização : Essa diferença de desempenho é explicada pelo fato de writeser altamente armazenado em buffer e retornar antes que qualquer gravação no disco ocorra (consulte esta resposta ), enquanto print(provavelmente) usa o buffer de linha. Um teste simples para isso seria verificar o desempenho também para gravações longas, onde as desvantagens (em termos de velocidade) do buffer de linha seriam menos pronunciadas.

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

A diferença de desempenho agora se torna muito menos acentuada, com um tempo médio de 2,20s para writee 3,10s para print. Se você precisar concatenar printvárias seqüências de caracteres para obter esse desempenho muito longo da linha, os casos de uso em que seria mais eficiente são um pouco raros.


10

Desde o 3.5, você também pode usar o pathlibpara esse fim:

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

Abra o arquivo apontado no modo de texto, grave dados e feche o arquivo:

import pathlib

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

5

Quando você disse Linha, significa alguns caracteres serializados que terminam em '\ n'. A linha deve ser a última em algum momento; portanto, devemos considerar '\ n' no final de cada linha. Aqui está a solução:

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

no modo de acréscimo após cada gravação, o cursor se move para a nova linha; se você quiser usar o wmodo, adicione \ncaracteres no final da write()função:

the_file.write("Hello\n")

1
"no modo de acréscimo após cada gravação, o cursor se move para a nova linha" - não, não é.
An Se

3

Pode-se também usar o iomódulo como em:

import io
my_string = "hi there"

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

1

Para escrever texto em um arquivo no balão, pode ser usado:

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

0

Você também pode tentar filewriter

pip install filewriter

from filewriter import Writer

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

Grava em my_file.txt

Pega um objeto iterável ou com __str__suporte.


0

Quando preciso escrever muitas linhas novas, defino um lambda que usa uma printfunção:

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

Essa abordagem tem o benefício de poder utilizar todos os recursos disponíveis com a printfunção.

Atualização: Como mencionado por Georgy na seção de comentários, é possível melhorar ainda mais essa idéia com a partialfunção:

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

IMHO, esta é uma abordagem mais funcional e menos enigmática.


2
Ou de outra maneira (provavelmente mais limpa) para escrever este: from functools import partial; fwl = partial(print, file=out).
Georgy

@ Georgy Sua abordagem é tão boa que pode ser dada como uma nova resposta.
MxNx

1
A ideia é a mesma que a sua, apenas a implementação é um pouco diferente. Se desejar, você pode adicioná-lo em uma edição à sua resposta. Eu estou bem com isso.
Georgy
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.