chricken
Anmeldungsdatum: 29. März 2007
Beiträge: 198
|
Hallo, ich will eine bestimmte Anzahl zufälliger Dateien aus einem Ordner in einen anderen kopieren.
Dazu wollte ich ein Python-Script von Audax verwenden: http://paste.pocoo.org/show/13821/ Der dazu passende Aufruf lautet:
| python ./autocopy.py -c AnzahlAnDateien Quellpfad Zielpfad
|
Wenn ich das auf meinem PC benutze funktioniert es einwandfrei.
Auf meinem Server allerdings nicht mehr. Beides sind Ubuntu 9.10, der Server ist allerdings ein Server - klar 😉 Auf dem Server bekomme ich diese Fehlermeldung:
| Traceback (most recent call last):
File "./autocopy.py", line 81, in <module>
main()
File "./autocopy.py", line 74, in main
for file in random_files:
File "./autocopy.py", line 44, in __iter__
files = [file for file in self.__files if file.decode('utf8') not in self.__allready.keys()]
File "/usr/lib/python2.6/encodings/utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 63-68: unsupported Unicode code range
|
Ich glaube, es so weit zu verstehen, dass Python mit dem bytes-kodierten Dateisystem nicht zurecht kommt.
Aber ich weiß nicht, wie ich das Problem beheben/umgehen kann. Kann mir da jemand weiterhelfen? Danke. Lieben Gruß Chricken
|
Lysander
Anmeldungsdatum: 30. Juli 2008
Beiträge: 2669
Wohnort: Hamburg
|
Die Fehlermeldung ist doch recht eindeutig: Das Script erwartet UTF-8 codierte Daten und Du gibst ihm offenbar Daten in einer anderen Codierung. Als Lösung müßtest Du entweder die Codierung der Daten ändern oder die korrekte Codierung im Script angeben.
|
Ferio
Anmeldungsdatum: 24. April 2007
Beiträge: 383
|
chricken schrieb: Aber ich weiß nicht, wie ich das Problem beheben/umgehen kann.
Einfach sämtlichen Kodierungs-Kram aus dem Script rausschmeißen.
|
Lysander
Anmeldungsdatum: 30. Juli 2008
Beiträge: 2669
Wohnort: Hamburg
|
Ferio schrieb: chricken schrieb: Aber ich weiß nicht, wie ich das Problem beheben/umgehen kann.
Einfach sämtlichen Kodierungs-Kram aus dem Script rausschmeißen.
OMG... was für ein Tipp...
|
DasIch
Anmeldungsdatum: 2. November 2005
Beiträge: 1130
|
Ist doch korrekt. Zum kopieren ist doch die Kodierung irrelevant.
|
Ferio
Anmeldungsdatum: 24. April 2007
Beiträge: 383
|
Lysander schrieb: Ferio schrieb: Einfach sämtlichen Kodierungs-Kram aus dem Script rausschmeißen.
OMG... was für ein Tipp...
Dateinamen haben nunmal per se keine Kodierung sondern sind beliebige Bytefolgen ohne NULL und „/“-Bytes. Dementsprechend ist es potentiell fehlerträchtig da einfach utf8 anzunehmen. Vor allem, wenn einen der Dateiname sowieso nicht interessiert(beim stumpfen Kopieren von Dateien).
|
Lysander
Anmeldungsdatum: 30. Juli 2008
Beiträge: 2669
Wohnort: Hamburg
|
Ferio schrieb: Lysander schrieb: Ferio schrieb: Einfach sämtlichen Kodierungs-Kram aus dem Script rausschmeißen.
OMG... was für ein Tipp...
Dateinamen haben nunmal per se keine Kodierung sondern sind beliebige Bytefolgen ohne NULL und „/“-Bytes.
Hm... und wie werden dann Umlaute dargestellt? Das ist doch bestimmt vom verwendeten Dateisystem abhängig! Nach irgend einem Schema muss man da ja vorgehen... Laut wikipedia ist dem auch so! Zudem würde dann auch ein Tool wie convmv sinnfrei sein...
Dementsprechend ist es potentiell fehlerträchtig da einfach utf8 anzunehmen.
Da hast Du sicherlich recht!
Vor allem, wenn einen der Dateiname sowieso nicht interessiert(beim stumpfen Kopieren von Dateien)
So gesehen habe ich das Script nicht ausreichend angeguckt. Allerdings stellt sich noch die Frage, wie os.path.join() dann arbeitet. Schließlich liegen die Dateinamen als Byte-Strings vor (Python 2.6) - wenn ich die dann mit anderen Bytes konkatenieren möchte, so muss die Funktion ja wissen, welche Kodierung die beiden Strings haben. Ansonsten käme es dabei ja zu Chaos. Diese Kodierungsthemen sind irgend wie immer lästig! 😀
|
Lunar
Anmeldungsdatum: 17. März 2006
Beiträge: 5792
|
@Lysander: Die Darstellung des Dateinamens hat nichts mit dem Dateisystem zu tun, denn das Dateisystem stellt nichts dar. Es assoziert nur eine Bytefolge als Namen mit der Datei. Die Darstellung bzw. die Interpretation dieser Bytes ist Sache des darstellenden Programms, welches üblicherweise die durch die Spracheinstellungen vorgegebene Kodierung heranzieht. Davon abgesehen hat Darstellung eines Dateinamens auch überhaupt nichts mit dem Thema zu tun, das Skript stellt keine Dateinamen dar. Insofern ist auch die Kodierung völlig irrelevant. Das Skript erhält einfach nur Bytes vom System, manipuliert diese Bytes, und gibt sie an das System zurück. Geschieht das in einer homogenen Umgebung, in der alles die selbe Kodierung hat (was bei Dateinamen normalerweise der Fall ist), funktioniert das völlig problemlos. Ist die Umgebung inhomogen, herrscht kodierungstechnisch eh schon Chaos. Dann ist es auch egal, dass das Verknüpfung unterschiedlich kodierter Dateinamen durch os.path.join fehlerhaft kodierte Dateinamen erzeugt. Um mit Dateinamen zu arbeiten, muss man deren Kodierung unter Linux nicht kennen, und die Dateinamen auch nicht interpretieren. Nur das Pfadtrennzeichen "/" ist vorgegeben, aber das bereits vom Systemkern. Man kann natürlich dekodieren, aber dann bitte mit "os.getfilesystemencoding()", und mit dem Risiko, dass es knallt, wenn der Nutzer Dateinamen in unterschiedlichen Kodierungen hat.
|
Lysander
Anmeldungsdatum: 30. Juli 2008
Beiträge: 2669
Wohnort: Hamburg
|
Lunar schrieb: Um mit Dateinamen zu arbeiten, muss man deren Kodierung unter Linux nicht kennen, und die Dateinamen auch nicht interpretieren. Nur das Pfadtrennzeichen "/" ist vorgegeben, aber das bereits vom Systemkern. Man kann natürlich dekodieren, aber dann bitte mit "os.getfilesystemencoding()", und mit dem Risiko, dass es knallt, wenn der Nutzer Dateinamen in unterschiedlichen Kodierungen hat.
Wie füge ich dann also am besten ein "ü" zu einem Dateinamen hinzu, wenn ich nur mit Bytes arbeite?
|
Ferio
Anmeldungsdatum: 24. April 2007
Beiträge: 383
|
Lysander schrieb: Dateinamen haben nunmal per se keine Kodierung sondern sind beliebige Bytefolgen ohne NULL und „/“-Bytes.
Hm... und wie werden dann Umlaute dargestellt? Das ist doch bestimmt vom verwendeten Dateisystem abhängig!
Nein, das ist von der verwendeten Anwendung abhängig. Dateinamen(POSIX) haben per se keine festgelegte Kodierung. Was das Dateissystem damit macht, ist wieder eine andere Sache, das erledigt der Treiber. Vor allem, wenn einen der Dateiname sowieso nicht interessiert(beim stumpfen Kopieren von Dateien)
So gesehen habe ich das Script nicht ausreichend angeguckt. Allerdings stellt sich noch die Frage, wie os.path.join() dann arbeitet. Schließlich liegen die Dateinamen als Byte-Strings vor (Python 2.6) - wenn ich die dann mit anderen Bytes konkatenieren möchte, so muss die Funktion ja wissen, welche Kodierung die beiden Strings haben. Ansonsten käme es dabei ja zu Chaos.
Nein, um ein "/"-Byte(\x47) zwischen zwei C-Strings einzufügen muss man die Kodierung der Strings nicht kennen. Später kann es in einer Anwendung, die eine konkrete Kodierung voraussetzt, durchaus zu einem Chaos kommen, wenn dieser String dann aus verschieden kodierten Teilstrings zusammengesetzt wurde. Deswegen ist es leider auch jetzt im 21. Jahrhundert noch ratsam, ASCII zu verwenden, damit kommen die meisten Programme klar.
Wie füge ich dann also am besten ein "ü" zu einem Dateinamen hinzu, wenn ich nur mit Bytes arbeite?
Gar nicht. Wenn du explizit ein „ü“ haben willst, musst du selbstverständlich irgendeine vorhandene Kodierung vorraussetzen. Dabei kannst du richtig raten oder nicht. So lange man aber weder ein „ü“ oder sonst einen Buchstaben haben möchte lässt man lieber die Finger von der Kodierung.
|
Lysander
Anmeldungsdatum: 30. Juli 2008
Beiträge: 2669
Wohnort: Hamburg
|
Ferio schrieb: Nein, um ein "/"-Byte(\x47) zwischen zwei C-Strings einzufügen muss man die Kodierung des Strings nicht kennen.
Weil "/" in allen existierenden Kodierungen den selben Byte-Wert hat?
|
Ferio
Anmeldungsdatum: 24. April 2007
Beiträge: 383
|
Lysander schrieb: Ferio schrieb: Nein, um ein "/"-Byte(\x47) zwischen zwei C-Strings einzufügen muss man die Kodierung des Strings nicht kennen.
Weil "/" in allen existierenden Kodierungen den selben Byte-Wert hat?
Nein, weil in POSIX-Dateinamen \x47 als Pfadtrenner vorgesehen ist. Zufälliger Weise ist das in ASCII nunmal ein „/“.
|
chricken
(Themenstarter)
Anmeldungsdatum: 29. März 2007
Beiträge: 198
|
Vielen Dank für Eure Antworten.
Das ist alles sehr interessant und ich habe mal wieder viel gelernt.
Aber wie kann ich das in die Tat umsetzen? Leider habe ich noch nie in Python gearbeitet, daher tue ich mich ein bisschen schwer, da etwas Sauberes auf die Beine zu stellen.
Kann mir jemand helfen, den Code so zu ändern, dass die zufälligen Dateien auch auf meinem Dateisystem kopiert werden können? Vielen Dank Chricken
|
Lysander
Anmeldungsdatum: 30. Juli 2008
Beiträge: 2669
Wohnort: Hamburg
|
Ferio schrieb: Lysander schrieb: Ferio schrieb: Nein, um ein "/"-Byte(\x47) zwischen zwei C-Strings einzufügen muss man die Kodierung des Strings nicht kennen.
Weil "/" in allen existierenden Kodierungen den selben Byte-Wert hat?
Nein, weil in POSIX-Dateinamen \x47 als Pfadtrenner vorgesehen ist. Zufälliger Weise ist das in ASCII nunmal ein „/“.
Ok, dann eben über den Byte-Wert. Also ist dieser in allen Codierungen identisch?
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Das hängt davon ab ... Die ersten 127 Codes (der ASCII-Bereich) sind eigentlich überall gleich. (Tabelle: http://de.wikipedia.org/wiki/American_Standard_Code_for_Information_Interchange#Zusammensetzung ) Die Unterschiede kommen bei allem über 127 (=hex 7F). Sieh mal zur Übersicht hier: http://de.wikipedia.org/wiki/Zeichensatz und im Einzelnen hier: http://de.wikipedia.org/wiki/ISO_8859 und hier: http://de.wikipedia.org/wiki/UTF-8
chricken: der einfachste Weg ist, das Skript auf dem Server mit dem gleichen "Locale" zu starten wie auf dem Desktop. Frag das doch auf beiden einmal ab mit locale, dann siehst Du die Unterschiede. Und wenn Du dann auf dem Server Dein Skript mit der selben Codierung wie zu Hause startest, mit LCALL=utf-8 davor (oder welche Codierung Du eben brauchst), dann könnte es schon klappen.
Wie füge ich dann also am besten ein "ü" zu einem Dateinamen hinzu, wenn ich nur mit Bytes arbeite?
Das wird doch Handarbeit. (jedenfalls mache ich das so). Also tatsächlich die richtigen Bytecodes mit der richtigen Codierung heraus suchen und als Bytecode (z.B. 0xC3 0xBC für Dein "ü" bei utf-8) eintragen ... - nee, nicht richtig bequem. Oder das Skript unter der selben Codierung laufen lassen, dann reicht ein "ü" aus. track
|