Richtiger Weg, um Zeile in Datei zu schreiben?

1069

Ich bin es gewohnt print >>f, "hi there"

Es scheint jedoch, dass print >> dass dies veraltet ist. Was ist der empfohlene Weg, um die obige Zeile auszuführen?

Update : In Bezug auf all diese Antworten mit "\n"... ist dies universell oder Unix-spezifisch? IE, sollte ich unter "\r\n"Windows tun ?

Jaroslaw Bulatow
quelle
11
"\ n" ist nicht Unix-spezifisch. Wenn die Datei im Textmodus (Standardeinstellung) geöffnet wird, wird sie automatisch in die richtige Zeilenende für die aktuelle Plattform übersetzt. Das Schreiben von "\ r \ n" würde "\ r \ r \ n" erzeugen, was falsch ist.
D Coetzee
Fügen Sie einfach die Anweisung print ord (os.linesep) hinzu, um den ASCII-Code zu sehen (10 auf den meisten UNIX-Systemen)
Stefan Gruenwald
Warum denkst du, ist es veraltet?
xxx ---

Antworten:

1153

Dies sollte so einfach sein wie:

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

Aus der Dokumentation:

Nicht os.linesepals Zeilenabschluss verwenden, wenn Dateien geschrieben werden, die im Textmodus geöffnet wurden (Standardeinstellung). Verwenden Sie stattdessen auf allen Plattformen ein einzelnes '\ n'.

Einige nützliche Lektüre:

Johnsyweb
quelle
37
Dieses Beispiel ist besser als das Beispiel zum Öffnen / Schließen. Die Verwendung withist eine sicherere Methode, um daran zu denken, eine Datei zu schließen.
Eyal
18
Ich muss nicht nennen the_file.close()?
Hussain
19
Nein, das tust du nicht: stackoverflow.com/questions/3012488/…
Tal Jerome
@Johnsyweb Warum sagst du "os.linesep. Es gibt viele gute Sachen in os!", Wenn du früher in dem Beitrag empfohlen hast, es nicht zu verwenden? Ich vermute hier eine Änderung, und es könnte der Grund für die Abstimmungen sein.
Horse SMith
1
@ user3226167: Das ist ein interessanter Punkt. Aber warum sollten Sie eine Binärdatei öffnen, um einfachen Text zu schreiben?
Johnsyweb
961

Sie sollten die print()Funktion verwenden, die seit Python 2.6+ verfügbar ist

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

Für Python 3 benötigen Sie das nicht import, da die print()Funktion die Standardeinstellung ist.

Die Alternative wäre zu verwenden:

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

Zitat aus der Python-Dokumentation zu Zeilenumbrüchen:

Wenn bei der Ausgabe newline None ist, werden alle '\n'geschriebenen Zeichen in das Standardzeilentrennzeichen des Systems übersetzt os.linesep. Wenn newline ist '', findet keine Übersetzung statt. Wenn newline einer der anderen zulässigen Werte ist, werden alle '\n'geschriebenen Zeichen in die angegebene Zeichenfolge übersetzt.

Sorin
quelle
35
-1 "Wenn Sie sicher sein möchten, fügen Sie der Zeichenfolge os.linesep hinzu, anstatt \n" würde newline = "erfordern", sonst würden Sie \r\r\nunter Windows erhalten. Es gibt überhaupt keinen Grund, sich mit os.linesep zu beschäftigen.
John Machin
7
@ Sorin: Ihre Bearbeitung zum Hinzufügen des Schreibmodus ist natürlich eine Verbesserung. Sie bleiben jedoch seltsamerweise unnachgiebig in Bezug auf os.linesep. Siehe meine Antwort. Die von Ihnen zitierte Dokumentation gilt übrigens für 3.x, aber dieser Teil gilt auch für 2.x im Textmodus: Alle geschriebenen '\ n' Zeichen werden in das Standardzeilentrennzeichen des Systems, os.linesep *, übersetzt . .. Windows: Das Schreiben von os.linesep ist dasselbe wie das Schreiben, \r\ndas enthält, \nwas in os.linesep übersetzt wird, was \r\ndas Endergebnis ist \r\r\n.
John Machin
7
@ John du hattest recht, ich habe den os.linesep Fehler behoben. Vielen Dank.
Sorin
3
Zum Anhängen ist es nicht open('myfile','a')stattdessen open('myfile','w')?
NeDark
6
@BradRuderman Dies ist Teil des POSIX- Standards für eine "Zeile" in einer Textdatei, dh jede Zeile in einer Textdatei muss durch eine neue Zeile abgeschlossen werden, auch die letzte Zeile.
Wheeler
116

Die Python-Dokumente empfehlen Folgendes :

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

So mache ich das normalerweise :)

Aussage von docs.python.org :

Es wird empfohlen, beim Umgang mit Dateiobjekten das Schlüsselwort 'with' zu verwenden . Dies hat den Vorteil, dass die Datei nach Abschluss der Suite ordnungsgemäß geschlossen wird, auch wenn unterwegs eine Ausnahme ausgelöst wird. Es ist auch viel kürzer als das Schreiben gleichwertiger Try-finally-Blöcke.

j7nn7k
quelle
1
Ich mag diesen Weg nicht, wenn ich das withInnere einer Schleife verschachteln muss . Dadurch öffne und schließe ich die Datei ständig, während ich in meiner Schleife fortfahre. Vielleicht fehlt mir hier etwas, oder das ist in diesem speziellen Szenario wirklich ein Nachteil?
Sibbs Gambling
38
Wie wäre es mit einer Schleife innerhalb des mit?
j7nn7k
@ j7nn7k für Linie in fd:
momstouch
86

In Bezug auf os.linesep:

Hier ist eine exakte unbearbeitete Python 2.7.1-Interpretersitzung unter 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'
>>>

Unter Windows:

Wie erwartet führt os.linesep NICHT zum gleichen Ergebnis wie '\n'. Es gibt keine Möglichkeit, das gleiche Ergebnis zu erzielen. 'hi there' + os.linesepist äquivalent zu 'hi there\r\n', was NICHT äquivalent zu ist 'hi there\n'.

So einfach ist das: use, \ndas automatisch in os.linesep übersetzt wird. Und so einfach ist es seit der ersten Portierung von Python auf Windows.

Es macht keinen Sinn, os.linesep auf Nicht-Windows-Systemen zu verwenden, und es führt unter Windows zu falschen Ergebnissen.

VERWENDEN SIE NICHT os.linesep!

John Machin
quelle
tolles Beispiel - neugierig, ob Sie ein Ipython-Benutzer sind? nette Funktionen zum Formatieren von Sitzungen
Alvin
Ich bin mir nicht ganz sicher, was Sie uns hier sagen wollen. os.linesep gibt den vom Betriebssystem definierten Zeilenbegriff (oder die Zeichenfolge) zurück. Windows verwendet standardmäßig \ r \ n für Zeilenenden. Es wird jedoch ein einzelnes \ n erkannt. Die Verwendung von \ n führt zu einem vollständig portablen AUSGANG, aber os.linesep ist unter Windows nicht falsch.
Gusdor
5
@Gusdor: Der Punkt ist, dass wenn Sie explizit os.linesepin Windows im Textmodus verwenden, das Ergebnis \r\r\nfalsch ist. "Windows verwendet ..." ist bedeutungslos. Die Laufzeitbibliothek C (und somit Python) übersetzen , \num \r\nim Textmodus auf ausgegeben. Andere Software verhält sich möglicherweise anders. Es ist NICHT der Fall, dass alle unter Windows ausgeführte Software \nbeim Lesen im Textmodus einen einzelnen als Trennzeichen erkennt . Python tut es. Der Notepad-Texteditor von Microsoft funktioniert nicht.
John Machin
6
Wahrscheinlich wird es jemand anderes lesen, nicht Sie, mit einer Mickey-Mouse-Software, die sich über das Extra lustig macht \r...
John Machin
2
@Gusdor kommst du aus einer anderen Sprache zu Python, wo die Verwendung von '\ n' zur Ausgabe von '\ n' im Fenster führt und nicht zu '\ r \ n' - daher fehlt das von dumm erwartete '\ r' Texteditoren? Wie John sagt, verhält sich Python nicht so - '\ n' wird automatisch durch '\ r \ n' ersetzt, wenn os.linesep dies vorschreibt. Daher os.linesep ist es hier "falsch" , explizit zu sagen . Es ist wie Department of Redundancy Department. Ja, du kannst es schaffen. Nein, das willst du nicht.
ToolmakerSteve
55

Ich glaube nicht, dass es einen "richtigen" Weg gibt.

Ich würde ... benutzen:

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

In Erinnerung an Tim Toady .

Hyperboreus
quelle
Aber das OP möchte möglicherweise zusätzliches Material in die Datei schreiben. Hier wird die Datei geschlossen, wenn der withGültigkeitsbereich verlassen wird.
Keith
Das könnte sein wollen open(..., 'a')oder sogar 'at'.
mtrw
5
Ähm, ja. Das ist die Idee mit zu verwenden. Wenn Sie die Datei offen halten möchten, rufen Sie einfach am Anfang auf und rufen Sie am Ende auf, wenn Sie fertig sind ...
Hyperboreus
1
@mtrw. Wahr. OP wurde angehängt.
Hyperboreus
1
Was Python betrifft, ist RIP Tim Toady - und das sehr, sehr, sehr zu Recht
Mr_and_Mrs_D
21

In Python 3 ist es eine Funktion, aber in Python 2 können Sie diese am Anfang der Quelldatei hinzufügen:

from __future__ import print_function

Dann tust du es

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

Wenn Sie viele Daten schreiben und Geschwindigkeit ein Problem ist, sollten Sie sich wahrscheinlich dafür entscheiden f.write(...). Ich habe einen schnellen Geschwindigkeitsvergleich durchgeführt und er war erheblich schneller als print(..., file=f)bei einer großen Anzahl von Schreibvorgängen.

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)

Im Durchschnitt writein 2.45s auf meiner Maschine beendet, währendprint etwa 4-mal so lange (9,76s) dauerte. In den meisten realen Szenarien ist dies jedoch kein Problem.

Wenn Sie sich dafür entscheiden, werden print(..., file=f)Sie wahrscheinlich feststellen, dass Sie die neue Zeile von Zeit zu Zeit unterdrücken oder durch etwas anderes ersetzen möchten. Dies kann durch Einstellen des optionalen endParameters erfolgen, z.

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

Welchen Weg Sie auch wählen, ich würde vorschlagen, ihn zu verwenden, withda er den Code viel einfacher zu lesen macht.

Update : Dieser Leistungsunterschied erklärt sich aus der Tatsache, dass er writestark gepuffert ist und zurückkehrt, bevor tatsächlich Schreibvorgänge auf die Festplatte stattfinden (siehe diese Antwort ), während print(wahrscheinlich) die Zeilenpufferung verwendet wird. Ein einfacher Test hierfür wäre, die Leistung auch für lange Schreibvorgänge zu überprüfen, bei denen die Nachteile (in Bezug auf die Geschwindigkeit) für die Zeilenpufferung weniger ausgeprägt wären.

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

Der Leistungsunterschied wird jetzt mit einer durchschnittlichen Zeit von 2,20 s für writeund 3,10 s für viel weniger ausgeprägt print. Wenn Sie eine Reihe von Zeichenfolgen verketten müssen, um diese lange Leitungsleistung zu erzielen, leidet dies unter Anwendungsfällen, bei denen printdies effizienter wäre.

Robin Keskisarkka
quelle
10

Seit 3.5 können Sie auch das pathlibfür diesen Zweck verwenden:

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

Öffnen Sie die Datei, auf die im Textmodus verwiesen wird, schreiben Sie Daten darauf und schließen Sie die Datei:

import pathlib

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

Wenn Sie Zeile sagten, bedeutet dies einige serialisierte Zeichen, die mit '\ n' Zeichen enden. Die Zeile sollte irgendwann die letzte sein, daher sollten wir am Ende jeder Zeile '\ n' berücksichtigen. Hier ist die Lösung:

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

Im Append-Modus bewegt sich der Cursor nach jedem Schreibvorgang in eine neue Zeile. Wenn Sie den wModus verwenden möchten, sollten Sie \nam Ende der write()Funktion Zeichen hinzufügen :

the_file.write("Hello\n")
Reza Tanzifi
quelle
1
"Im Append-Modus bewegt sich der Cursor nach jedem Schreiben in eine neue Zeile" - nein, ist es nicht.
Ein Se
3

Man kann das ioModul auch wie folgt verwenden:

import io
my_string = "hi there"

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

So schreiben Sie Text in eine Datei in der Flasche:

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

Sie können es auch versuchen filewriter

pip install filewriter

from filewriter import Writer

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

Schreibt in my_file.txt

Nimmt eine iterable oder ein Objekt mit __str__Unterstützung.

Emin Bugra Saral
quelle
0

Wenn ich viel neue Zeilen schreiben muss, definiere ich ein Lambda, das eine printFunktion verwendet:

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

Dieser Ansatz hat den Vorteil, dass alle mit der printFunktion verfügbaren Funktionen genutzt werden können.

Update: Wie von Georgy im Kommentarbereich erwähnt, ist es möglich, diese Idee mit der partialFunktion weiter zu verbessern :

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

Meiner Meinung nach ist dies ein funktionaler und weniger kryptischer Ansatz.

MxNx
quelle
2
Oder eine andere (wahrscheinlich sauberere) Art, dies zu schreiben : from functools import partial; fwl = partial(print, file=out).
Georgy
@Georgy Ihr Ansatz ist so gut, dass er als neue Antwort gegeben werden kann.
MxNx
1
Die Idee ist die gleiche wie bei Ihnen, nur die Implementierung ist etwas anders. Wenn Sie möchten, können Sie es Ihrer Antwort in einer Bearbeitung hinzufügen. Ich bin damit einverstanden.
Georgy