systemabhängige newline-Konstante wie os.path.sep

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
droptix
User
Beiträge: 521
Registriert: Donnerstag 13. Oktober 2005, 21:27

Um eine Datei für das jeweils eingesetzte Betriebssystem leserlich zu schreiben, wäre eine Konstante wie `newline` sinnvoll. Diese soll den String
  • • "\n" unter Unix
    • "\r\n" unter Windows
    • "\r" unter Mac OS 9 etc.
repräsentieren. Mit `os.path.sep` gibt es sowas ja auch für den Verzeichnistrenner im Dateisystem.

Hab davon auch schonmal was gehört, aber weder in meinem Büchlein oder dem Forum hier was konkretes gelesen. Gibt's sowas?
BlackJack

Genau das ist doch der Sinn der Unterscheidung von Text- und Binärdateien. Im Programm ist '\n' das Zeilenende und beim schreiben und lesen von Textdateien wird dieses Zeichen für den Benutzer transparent in die jeweilige Zeichenkombination des Betriebssystems übersetzt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

droptix hat geschrieben:wäre eine Konstante wie `newline` sinnvoll.
Hi droptix!

Gibt es --> ``os.linesep``

Wenn du aber eine Datei so ``f = file("filename.txt", "w)`` öffnest, dann übernimmt Python das Schreiben der korrekten Zeilenenden.

Dieser Code:

Code: Alles auswählen

f = file(r"filename.txt", "w")
f.write("asdf\n")
f.close()
Schreibt unter Linux ein "\n", unter Mac ein "\r" und unter Windows ein "\r\n" in die Datei.

Wenn du das verhindern möchtest, dann musst du die Datei im Binärmodus öffnen.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
droptix
User
Beiträge: 521
Registriert: Donnerstag 13. Oktober 2005, 21:27

BlackJack hat geschrieben:Genau das ist doch der Sinn der Unterscheidung von Text- und Binärdateien.
Was hat das mit meinem Problem zu tun?

Oder anders formuliert: Wenn ich nur ein "\n" an jedes Zeilenende hänge, stellt z.B. der Editor notepad.exe unter Windows keine Zeilenumbrüche dar. Das möchte ich unbedingt vermeiden, will aber auch nicht pauschal ein "\r\n" anhängen, weil das für andere Betriebssysteme unsauber ist.

Ich könnte mir eine Unterscheidung bauen, indem ich die Plattform auslesen und versuche das sinnvoll zu parsen. Aber dabei kann ich unmöglich alle Plattformen berücksichtigen. Eine globale Python-Konstante wäre sinnvoll.

Also wie kriege ich das sauber für alle Plattformen hin?
droptix
User
Beiträge: 521
Registriert: Donnerstag 13. Oktober 2005, 21:27

gerold hat geschrieben:Gibt es --> ``os.linesep``

Wenn du aber eine Datei so ``f = file("filename.txt", "w)`` öffnest, dann übernimmt Python das Schreiben der korrekten Zeilenenden.

Dieser Code […] Schreibt unter Linux ein "\n", unter Mac ein "\r" und unter Windows ein "\r\n" in die Datei.
Aaaaaah! Da haste wohl recht! Bei mir tritt das Problem auf, weil ich

Code: Alles auswählen

x = ["spam", "eggs"]
f = file(r"filename.txt", "w")
f.writelines(x)
f.close()
verwendet habe. Ergibt nämlich im Notepad:

Code: Alles auswählen

spameggs
EDIT: Habe es nun wie folgt geändert und es funktioniert einwandfrei!

Code: Alles auswählen

x = ["spam", "eggs"]
f = file(r"filename.txt", "w")
f.write(os.linesep.join(x))
f.close()
Wer lesen kann ist klar im Vorteil:
Python Documentation hat geschrieben:writelines( sequence)
Write a sequence of strings to the file. The sequence can be any iterable object producing strings, typically a list of strings. There is no return value. (The name is intended to match readlines(); writelines() does not add line separators.)
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

droptix hat geschrieben:

Code: Alles auswählen

x = ["spam", "eggs"]
f = file(r"filename.txt", "w")
f.write(os.linesep.join(x))
f.close()
Hi droptix!

Das solltest du aber vermeiden. Dein Code sollte eher so aussehen:

Code: Alles auswählen

#so 
x = ["spam", "eggs"]
f = file(r"filename.txt", "w")
f.write("\n".join(x))
f.close()

# oder so
x = ["spam", "eggs"]
f = file(r"filename.txt", "w")
f.writelines("%s\n" % line for line in x)
f.close()

# oder so
x = ["spam", "eggs"]
f = file(r"filename.txt", "w")
for line in x:
    f.write(line + "\n")
f.close()
Aber auf keinen Fall so:

Code: Alles auswählen

x = ["spam", "eggs"]
f = file(r"filename.txt", "w")
f.write(os.linesep.join(x))
f.close()
Vielleicht noch so:

Code: Alles auswählen

x = ["spam", "eggs"]
f = file(r"filename.txt", "wb")
f.write(os.linesep.join(x))
f.close()
;-)

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

...was ich damit sagen wollte:

Wenn du die Datei im Binärmodus öffnest, dann musst du dich selber um die richtigen Zeilenenden kümmern. Wenn du die Datei aber im "normalen" Textmodus öffnest, dann wandelt Python ein "\n" beim Schreiben in das richtige Zeilenende um. Wenn du aber eine Datei im Textmodus öffnest und "\r\n" (was du ja mit ``os.linesep`` machst) als Zeilenumbruch verwendest, dann ist das irgendwie doppelt gemoppelt. DU kümmerst dich um den richtigen Zeilenumbruch und Python macht das nochmal. Diesmal vielleicht sogar falsch.

Ich korrigiere: Es ist garantiert falsch:

Code: Alles auswählen

>>> f = file(r"eintext.txt", "w")
>>> f.write("asdf" + os.linesep)
>>> f.write("jjjj" + os.linesep)
>>> f.close()
>>> f = file(r"eintext.txt", "rb")
>>> print repr(f.read())
'asdf\r\r\njjjj\r\r\n'
>>>
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
droptix
User
Beiträge: 521
Registriert: Donnerstag 13. Oktober 2005, 21:27

Ah, verstehe. Aber solange ich die Datei nicht im Binärmodus öffne, ist das doch eigentlich egal, oder?

`os.linesep` ist ja eine Konstante und daher genauso verwendbar wie "\n". Die Gefahr beim Binärmodus ist aber jetzt klar geworden, also Danke!
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Nein wenn du im Textmodus ein os.linesep unter Windows (\r\n) speicherst, sperichert Python ein \r\r\n, weil ein \n unter Windows ein \r\n wird.

Du kannst in deinem Programm immer \n verwenden, wenn du die Datei im Textmodus geöffnet hast, Python kümmert sich dann um die korrekte umwandlung für die verschiedenen Systeme.

os.linesep brauchst du nur, wenn du eine Datei im Binärmodus geöffnet hast und einen Zeilenumbruch reinschreiben willst.

Gruss
droptix
User
Beiträge: 521
Registriert: Donnerstag 13. Oktober 2005, 21:27

Jetzt hat es endgültig KLICK gemacht! Ich liebe eure schnellen Antworten und eure Geduld mit mir :P
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Es gibt auch noch den Universal Newline Support (PEP 278), und hier ein Anwendungsbeispiel.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten