os.listdir und filesystemencoding

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.
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 30. März 2006, 10:10

Unter Windows funktioniert das tadellos:

Code: Alles auswählen

        for item in os.listdir(self.absolute_path):
            try:
                codec = self.request.context["filesystemencoding"]
                item = item.decode(codec)
                item = item.encode("utf-8")
            except UnicodeError, e:
                self.request.write(
                    "<small>(Unicode-Error: %s)</small><br />" % e
                )
                pass
            self.request.write(
                "<small>%s</small><br />" % item.encode("String_Escape")
            )
Es gibt unter Windows keine Unicode-Fehler. Das filesystemencoding ist mbcs

Unter Linux (ubuntu) klappt das aber nicht es gibt Fehler, wie diese:
'ascii' codec can't decode byte 0xc3 in position 10: ordinal not in range(128)
Das filesystemencoding ist ANSI_X3.4-1968 Wenn ich mir allerdings die Ausgabe der Dateinamen ansehe, sieht das für mich wie UTF-8 aus. z.B. "B\xc3\xbchne" (String_Escape) ist "Bühne"

Warum klappt das unter Linux nicht?

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Donnerstag 30. März 2006, 14:08

Ich glaube nicht, dass das Linuxdateisystem sich um das Encoding schert, leider.

Manche Programme legen bei mir Dateien im UTF-8 an, andere wiederum in Latin-1.

Das "ls" sieht dementsprechend auch lustig aus... :(
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Donnerstag 30. März 2006, 15:18

jens hat geschrieben:Warum klappt das unter Linux nicht?
Hi Jens!

Nur um sicher zu gehen. self.request.context["filesystemencoding"] liefert das gleiche Encoding wie os.getfilesystemencoding()?

lg
Gerold
:-)
[url]http://halvar.at[/url] | [url=http://halvar.at/elektronik/kleiner_bascom_avr_kurs/]Kleiner Bascom AVR Kurs[/url]
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 30. März 2006, 15:36

gerold hat geschrieben:Nur um sicher zu gehen. self.request.context["filesystemencoding"] liefert das gleiche Encoding wie os.getfilesystemencoding()?
Nein, ich hab sys.getfilesystemencoding() genommen... Oder hast du dich verschrieben?

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Donnerstag 30. März 2006, 15:42

jens hat geschrieben:Oder hast du dich verschrieben?
Hi Jens!

Ich frage deshalb, weil du in deinem Beispielcode self.request.context["filesystemencoding"] und nicht sys.getfilesystemencoding() verwendest. :?: Ich weiß ja nicht, was self.request.context["filesystemencoding"] zurück liefert und ob das wirklich das Filesystemencoding ist.

lg
Gerold
:-)
[url]http://halvar.at[/url] | [url=http://halvar.at/elektronik/kleiner_bascom_avr_kurs/]Kleiner Bascom AVR Kurs[/url]
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 30. März 2006, 15:44

Stimmt, aber es ist im Prinzip so:

Code: Alles auswählen

self.request.context["filesystemencoding"] = sys.getfilesystemencoding()

        for item in os.listdir(self.absolute_path):
            try:
                codec = self.request.context["filesystemencoding"]
                item = item.decode(codec)
                item = item.encode("utf-8")
            except UnicodeError, e:
                self.request.write(
                    "<small>(Unicode-Error: %s)</small><br />" % e
                )
                pass
            self.request.write(
                "<small>%s</small><br />" % item.encode("String_Escape")
            )
:lol:

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Donnerstag 30. März 2006, 15:59

Hi Jens!

Code: Alles auswählen

        for item in os.listdir(self.absolute_path):
            item = item.decode("Eigenes Scriptcoding")
            item = item.encode("utf-8")
            self.request.write(
                "<small>%s</small><br />" % item.encode("String_Escape")
            )
Ich glaube nicht, dass der eingebaute Befehl "os.listdir()" dir die Daten im Filesystemencoding zurück gibt. Ich glaube eher, dass er dir die Daten im Encoding deines Skriptes zurück gibt. Genau wissen tu ich es aber nicht. :wink:

lg
Gerold
:-)
[url]http://halvar.at[/url] | [url=http://halvar.at/elektronik/kleiner_bascom_avr_kurs/]Kleiner Bascom AVR Kurs[/url]
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 30. März 2006, 16:27

Tja, keine Ahnung... Auf jeden Fall funktioniert das unter Linux und Windows unterschiedlich... Aber vielleicht sollte ich mal einen Test außerhab von WebServer/CGI machen ;)

Aber das wird heute nix mehr...

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

Donnerstag 30. März 2006, 22:36

`os.listdir()` gibt die Dateinamen als Unicode-Zeichenketten zurück, wenn man auch den Pfadnamen als Unicode-Zeichenkette übergibt. Wie sieht's dann bei Dir aus?
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

Donnerstag 30. März 2006, 23:36

Unter Unix gibts sowas wie ein Filesystem-Encoding auf Dateisystemebene prinzipiell erst mal nicht. Auf der Platte stehen nur Byte-Strings, die dann zumindest unter Linux vom VFS (dem virtuellen Dateisystem des Kernels, das die Devices abstrahiert) entsprechend der Mount-Option des Dateisystems interpretiert werden, allerdings dem Userspace immer noch als Binär-Strings zur Verfügung gestellt werden, und zwar in dem Encoding was als Standard-Encoding ausgewählt wurde beim compilieren des Kernels. Sowas wie Unicode-fähige Syscalls (wie unter Windows) gibts nicht.

Siehe hierzu am besten:

Code: Alles auswählen

man mount
Da steht ziemlich viel drin wie das Filesystem-Encoding unter Linux funktioniert...
--- Heiko.
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 31. März 2006, 06:55

OK, also ich mach es jetzt so:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import sys, dircache

for item in dircache.listdir("."):
    codec = sys.getfilesystemencoding()
    if codec == "mbcs":
        # f&#56480;Windows
        try:
            item = item.decode(codec).encode("utf-8")
        except UnicodeError, e:
            print ">>>Unicode-Error: %s" % e

    try:
        first_letter = item.decode("utf-8") # nach unicode wandeln
        first_letter = first_letter[0].upper()
        first_letter = first_letter.encode("utf-8") # zurück konvertieren
    except UnicodeError, e:
        print ">>>Unicode-Error 'first_letter': %s" % e
        first_letter = "#"

    print type(item), first_letter, "-", first_letter.encode("String_Escape")
    print item.encode("String_Escape")
    print item

    print
Hab direk das "first_letter"-Problem von http://www.python-forum.de/viewtopic.php?t=5579 angehängt...

Das scheit für mich erstmal gut zu funktionieren... Ist es die beste Lösung?

@BlackJack: dircache mag allerdings als Pfadangabe nur string, kein unicode...

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Montag 3. April 2006, 21:28

Also ich komm einfach nicht auf einen grünen Zweig....

Nun hab ich es versucht os.listdir() mit einem unicode-Pfad zu füttern...

Unter Windows habe ich dann alle Dateinamen als unicode... Unter Linux aber nur die, in denen _keine_ Sonderzeichen vorkommen :shock: Also ein Mischmasch :evil:

Die einzige Variante die funktioniert, ist einfach alle Dateinamen/Pfade zu ignorieren, in denen Sonderzeichen vorkommen. Aber das ist ja wohl nicht wirklich eine Lösung :cry:

EDIT: Wenn ich nun unter Linux versuche die nicht unicode Einträge in unicode zuwandlen, klappt das mit utf-8 erstmal... Später hab ich allerdings probleme.
os.path.isfile() funktioniert nicht mehr! Es sagt, das der Eintrag eine Datei ist, es ist aber ein Verzeichniss!
Mit os.stat() bekommte ich dann einen UnicodeEncodeError :evil:

Ich bau mir jetzt nochmal ein kleines Testscript und poste das mal...

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dienstag 4. April 2006, 08:19

So, ich hab ein kleines Test-Skript. Im Testverz. sind folgenden Einträge:
  • <verz> dir eins
    <verz> dir zwei äöüß
    <datei> file eins.txt
    <datei> file zwei äöüß.txt

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import sys, os

stdout_encoding = sys.stdout.encoding or sys.getfilesystemencoding()
print "stdout_encoding:", stdout_encoding



def filesystemTest(listPath):
    absolute_path = os.getcwd()

    print "-"*79
    print "absolute_path:", absolute_path
    print "listPath:", listPath
    print

    dirList = os.listdir(listPath)
    try:
        dirList.sort()
    except UnicodeError, e:
        print "sort() ERROR:", e

    for item in dirList:
        print type(item),
        if isinstance(item, unicode):
            try:
                print item.encode(stdout_encoding)
            except UnicodeError, e:
                print "ERROR 1:", e
        else:
            print item

        abs_path = os.path.join(absolute_path, item)
        print type(abs_path),
        if isinstance(item, unicode):
            try:
                print abs_path.encode(stdout_encoding)
            except UnicodeError, e:
                print "ERROR 2:", e
        else:
            print abs_path

        print "file: %s, dir: %s" % (os.path.isfile(abs_path), os.path.isdir(abs_path))

        try:
            abs_path = abs_path.decode(sys.getfilesystemencoding())
            print "file: %s, dir: %s" % (os.path.isfile(abs_path), os.path.isdir(abs_path))
        except UnicodeError, e:
            print "ERROR 3:", e

        print


#~ filesystemTest("FilesystemUnicodeTest")
#~ filesystemTest(u"FilesystemUnicodeTest")

filesystemTest("FilesystemUnicodeTestLinux")
filesystemTest(u"FilesystemUnicodeTestLinux")
Ausgaben Windows:

Code: Alles auswählen

stdout_encoding: mbcs
-------------------------------------------------------------------------------
absolute_path: W:\PyDown\PyDown
listPath: FilesystemUnicodeTest

<type 'str'> dir eins
<type 'str'> W:\PyDown\PyDown\dir eins
file: False, dir: False
file: False, dir: False

<type 'str'> dir zwei äöüß
<type 'str'> W:\PyDown\PyDown\dir zwei äöüß
file: False, dir: False
file: False, dir: False

<type 'str'> file eins.txt
<type 'str'> W:\PyDown\PyDown\file eins.txt
file: False, dir: False
file: False, dir: False

<type 'str'> file zwei äöüß.txt
<type 'str'> W:\PyDown\PyDown\file zwei äöüß.txt
file: False, dir: False
file: False, dir: False

-------------------------------------------------------------------------------
absolute_path: W:\PyDown\PyDown
listPath: FilesystemUnicodeTest

<type 'unicode'> dir eins
<type 'unicode'> W:\PyDown\PyDown\dir eins
file: False, dir: False
file: False, dir: False

<type 'unicode'> dir zwei äöüß
<type 'unicode'> W:\PyDown\PyDown\dir zwei äöüß
file: False, dir: False
ERROR 3: 'ascii' codec can't encode characters in position 26-29: ordinal not in range(128)

<type 'unicode'> file eins.txt
<type 'unicode'> W:\PyDown\PyDown\file eins.txt
file: False, dir: False
file: False, dir: False

<type 'unicode'> file zwei äöüß.txt
<type 'unicode'> W:\PyDown\PyDown\file zwei äöüß.txt
file: False, dir: False
ERROR 3: 'ascii' codec can't encode characters in position 27-30: ordinal not in range(128)

EDIT:
So jetzt das ganze unter Linux:

Code: Alles auswählen

stdout_encoding: UTF-8
-------------------------------------------------------------------------------
absolute_path: /daten/www/PyDown/PyDown
listPath: FilesystemUnicodeTestLinux

<type 'str'> dir eins
<type 'str'> /daten/www/PyDown/PyDown/dir eins
file: False, dir: False
file: False, dir: False

<type 'str'> dir zwei äöüß
<type 'str'> /daten/www/PyDown/PyDown/dir zwei äöüß
file: False, dir: False
ERROR 3: 'utf8' codec can't decode bytes in position 34-36: invalid data

<type 'str'> file eins.txt
<type 'str'> /daten/www/PyDown/PyDown/file eins.txt
file: False, dir: False
file: False, dir: False

<type 'str'> file zwei äöüß
<type 'str'> /daten/www/PyDown/PyDown/file zwei äöüß
file: False, dir: False
ERROR 3: 'utf8' codec can't decode bytes in position 35-37: invalid data

-------------------------------------------------------------------------------
absolute_path: /daten/www/PyDown/PyDown
listPath: FilesystemUnicodeTestLinux

sort() ERROR: 'ascii' codec can't decode byte 0xe4 in position 9: ordinal not in range(128)
<type 'unicode'> dir eins
<type 'unicode'> /daten/www/PyDown/PyDown/dir eins
file: False, dir: False
file: False, dir: False

<type 'str'> dir zwei äöüß
<type 'str'> /daten/www/PyDown/PyDown/dir zwei äöüß
file: False, dir: False
ERROR 3: 'utf8' codec can't decode bytes in position 34-36: invalid data

<type 'unicode'> file eins.txt
<type 'unicode'> /daten/www/PyDown/PyDown/file eins.txt
file: False, dir: False
file: False, dir: False

<type 'str'> file zwei äöüß
<type 'str'> /daten/www/PyDown/PyDown/file zwei äöüß
file: False, dir: False
ERROR 3: 'utf8' codec can't decode bytes in position 35-37: invalid data

Was ich jetzt gerad überhaupt nicht verstehe, das isfile() und isdir() immer false sind :shock: Das kann eigentlich nicht wirklich sein!

Unter Linux klappt komischerweise sort() auch nicht :shock: Ein Test mit sorted() klappt auch nicht...

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

Dienstag 4. April 2006, 08:44

Jens, lies Dir man mount und Filesystem-Encoding da mal durch... Wie ich bereits sagte funktioniert die Kommunikation mit dem Userspace immer als Binär-Datenstrom, nicht per Unicode...

Warum mußt Du eigentlich umbedingt wissen mit welchem Dateinamen-Encoding der File auf der Platte liegt?
--- Heiko.
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dienstag 4. April 2006, 09:13

modelnine hat geschrieben:Warum mußt Du eigentlich umbedingt wissen mit welchem Dateinamen-Encoding der File auf der Platte liegt?
Also wirklich wissen möchte ich das nicht... Ich möchte nur einfach das Dateinamen (WSGI-WebApp) richtig im Browser dagestellt werden, auch wenn sie Sonderzeichen haben ;)

Da ich die Webseiten als UTF-8 sende (über jinja mit charset=UTF8) brauche ich also unicode oder direkt UTF-8... Wie ich das jetzt anstelle, weiß ich allerdings nicht...

EDIT: es ist eine ext3 Partition, auszug aus der fstab:

Code: Alles auswählen

/dev/hda6  /daten  ext3  suid,dev,exec  0  1
EDIT2: Hab noch was gefunden zum Thema ( http://www.amk.ca/python/howto/unicode ):
MacOS X uses UTF-8 while Windows uses a configurable encoding; on Windows, Python uses the name "mbcs" to refer to whatever the currently configured encoding is. On Unix systems, there will only be a filesystem encoding if you've set the LANG or LC_CTYPE environment variables; if you haven't, the default encoding is ASCII.
LANG ist bei mir de_DE.UTF-8

Und noch was gefunden: http://kofoto.rosdahl.net/trac/wiki/UnicodeInPython (unter File system):
os.listdir

os.listdir(u"path") returns Unicode strings for names that can be decoded with sys.getfilesystemencoding() but silently returns byte strings for names that can't be decoded. That is, the return value of os.listdir(u"path") is potentially a mixed list of Unicode and byte strings.
...
os.path

On Unix, os.path.abspath throws UnicodeDecodeError when given a Unicode string with a relative path and os.getcwd() returns a non-ASCII binary string (or rather: a non-sys.getdefaultencoding()-encoded binary string). Therefore, the argument must be a byte string. On Windows, however, the argument must be a Unicode string so that the "wide" API calls are used. This leads to the nasty situation that a work-around is needed, but only on Unix:

Code: Alles auswählen

if os.name == "posix":
    fs_enc = sys.getfilesystemencoding()
    def abspath(path):
        return os.path.abspath(path.encode(fs_enc)).decode(fs_enc)
else:
    abspath = os.path.abspath
x = abspath(u"path")
Demnach muß ich wohl einige work-a-round's einbauen, was? :(

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten