Seite 1 von 1

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

Verfasst: Samstag 3. März 2007, 21:40
von droptix
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?

Verfasst: Samstag 3. März 2007, 22:16
von 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.

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

Verfasst: Samstag 3. März 2007, 22:30
von gerold
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
:-)

Verfasst: Samstag 3. März 2007, 22:34
von droptix
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?

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

Verfasst: Samstag 3. März 2007, 22:38
von droptix
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.)

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

Verfasst: Samstag 3. März 2007, 22:48
von gerold
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
:-)

Verfasst: Samstag 3. März 2007, 22:51
von gerold
...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
:-)

Verfasst: Samstag 3. März 2007, 23:20
von droptix
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!

Verfasst: Samstag 3. März 2007, 23:32
von rayo
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

Verfasst: Sonntag 4. März 2007, 01:04
von droptix
Jetzt hat es endgültig KLICK gemacht! Ich liebe eure schnellen Antworten und eure Geduld mit mir :P

Verfasst: Sonntag 4. März 2007, 12:30
von Leonidas
Es gibt auch noch den Universal Newline Support (PEP 278), und hier ein Anwendungsbeispiel.