Python 3.5: os.walk(), os.scandir() und os.DirEntry

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

Also irgendwie verstehe ich das noch nicht...

Es gibt das neue os.scandir(), als ersatz für os.listdir(): https://docs.python.org/3/library/os.html#os.scandir
os.scandir() spuckt das neue os.DirEntry() instanzen aus...

Das alte os.walk() nutzt zwar os.scandir() und hat somit die os.DirEntry() instanzen, liefert aber, wie bei der alten API nur die Pfade, aber nicht die Instanz :(

Aber das wäre doch hilfreich...

Was tun? Den code von os.walk() duplizieren und abändern, damit er os.DirEntry() instanzen auswirft?!?
Ist doch auch doof.

Dann gibt es das neue pathlib.Path()... Könnte ja ebenfalls bei os.walk() Verwendung finden...

Ist ein os.walk2() oder so, in mache?!? Der dann das alles "Verbindet" ?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

jens hat geschrieben:Ist ein os.walk2() oder so, in mache?!? Der dann das alles "Verbindet" ?
Nicht, dass ich wüsste. Aber du kannst ein rekursives `scandir()` relativ leicht selbst implementieren:

Code: Alles auswählen

def scantree(path):
    """Recursively yield DirEntry objects for given directory."""
    for entry in scandir(path):
        if entry.is_dir(follow_symlinks=False):
            yield from scantree(entry.path)
        else:
            yield entry
Quelle: http://stackoverflow.com/a/33135143
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hm! Hab was dummes gefunden... Zumindest für Windows :(

Unter Windows gibt es ja die Katastrophe mit den "Schein Verzeichnissen". Damit alte Programme in alten Pfaden schreiben können, diese aber auf neue Pfade umgeleitet werden usw...

Heißen Junction und meinen wohl sowas wie symlinks :P

Kann man in der cmd.exe sich z.B. so anzeigen lassen:

Code: Alles auswählen

C:\>cd /d %LOCALAPPDATA%

C:\Users\jens\AppData\Local>dir /al
 Datenträger in Laufwerk C: ist Win10 1
 Volumeseriennummer: 9E8F-2FF3

 Verzeichnis von C:\Users\jens\AppData\Local

18.01.2016  08:52    <JUNCTION>     Anwendungsdaten [C:\Users\jens\AppData\Local]
18.01.2016  08:52    <JUNCTION>     Temporary Internet Files [C:\Users\jens\AppData\Local\Microsoft\Windows\INetCache]
18.01.2016  08:52    <JUNCTION>     Verlauf [C:\Users\jens\AppData\Local\Microsoft\Windows\History]
               0 Datei(en),              0 Bytes
               3 Verzeichnis(se), 19.210.612.736 Bytes frei
Ein os.walk() ignoriert diese (Selbst bei followlinks=True)...
Ein os.scandir() allerdings nicht :(

Das dumme: C:\Users\jens\AppData\Local\Anwendungsdaten zeigt auf: C:\Users\jens\AppData\Local :shock:
Also eine schöne verschachtelte Endlosschleife, wenn man da mit os.scandir() rekursiv durchwandert :evil:

Zum selbst probieren: os.walk() listet u.a. Anwendungsdaten nicht:

Code: Alles auswählen

for root, dirs, files in os.walk(os.environ["LOCALAPPDATA"], followlinks=True):
    print(root)

Mit os.scandir():

Code: Alles auswählen

for entry in os.scandir(os.environ["LOCALAPPDATA"]):
    print(entry)
Listet u.a.: <DirEntry 'Anwendungsdaten'>, <DirEntry 'Temporary Internet Files'> und <DirEntry 'Verlauf'> auf...
Dabei ist ein entry.is_symlink() immer False
Aber auch os.path.islink(entry.path) liefert immer False


Also os.walk() versucht eigentlich auch in der Verzeichnis wie C:\Users\jens\AppData\Local\Anwendungsdaten rein zu gehen... Aber das anschließende os.listdir() schlägt fehl... Sieht man aber erstmal nicht, aber so:

Code: Alles auswählen

def walk_error(err):
    print("Error: %s" % err)

for root, dirs, files in os.walk(os.environ["LOCALAPPDATA"], onerror=walk_error, followlinks=True):
    pass
Liefert dann:
Error: [WinError 5] Zugriff verweigert: 'C:\\Users\\jens\\AppData\\Local\\Anwendungsdaten'
Error: [WinError 5] Zugriff verweigert: 'C:\\Users\\jens\\AppData\\Local\\Microsoft\\Windows\\INetCache\\Content.IE5'
Error: [WinError 5] Zugriff verweigert: 'C:\\Users\\jens\\AppData\\Local\\Microsoft\\Windows\\Temporary Internet Files'
Error: [WinError 5] Zugriff verweigert: 'C:\\Users\\jens\\AppData\\Local\\Temporary Internet Files'
Error: [WinError 5] Zugriff verweigert: 'C:\\Users\\jens\\AppData\\Local\\Verlauf'
...und deswegen fehlen die...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Als test fällt mir nicht viel ein, außer pathlib.Path().resolve() zu nutzten, denn der Pfad C:\Users\jens\AppData\Local\Anwendungsdaten wird dabei zu: C:\Users\jens\AppData\Local

Also sowas:

Code: Alles auswählen

def resolveable(path):
    path = pathlib.Path(path)
    test = path.resolve()
    return path == test

for entry in os.scandir(os.environ["LOCALAPPDATA"]):
    print(entry, resolveable(entry.path))
Liefert dann u.a.:

Code: Alles auswählen

<DirEntry 'Adobe'> True
<DirEntry 'Anwendungsdaten'> False
<DirEntry 'Autodesk'> True
...
<DirEntry 'Temp'> True
<DirEntry 'Temporary Internet Files'> False
<DirEntry 'Thunderbird'> True
<DirEntry 'TileDataLayer'> True
<DirEntry 'Verlauf'> False
<DirEntry 'VirtualStore'> True

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Was mir auch gerade mal so auffällt, ist die schlechte "integration" von pathlib :evil:

Also das geht nicht:

Code: Alles auswählen

src = pathlib.Path("/foo/")
dsr = pathlib.Path("/bar/")
os.link(src, dsr)
Es gibt zwar ein Path.unlink() und ein Path.symlink_to() aber keinen Ersatz für os.link() :evil:

Und weil .path erst mit 3.4.5 und 3.5.2 aufgenommen wurde (s. https://docs.python.org/3/library/pathl ... ePath.path ), kann man nicht das machen:

Code: Alles auswählen

os.link(src.path, dsr.path)
Also, wenn man ältere Versionen unterstützen möchte, dann geht nur das:

Code: Alles auswählen

os.link(str(src), str(dsr))
Was komisch wirkt.

EDIT: Wobei ich mich gerade frage, ob ich nicht auch auf den support von <3.4.5 und <3.5.2 verzichten kann?!?
EDIT: Auf keinen Fall 3.5.2 ist ja nichtmal draußen :roll:

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten