Seite 1 von 1

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

Verfasst: Montag 28. Dezember 2015, 21:37
von jens
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" ?

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

Verfasst: Dienstag 29. Dezember 2015, 09:24
von snafu
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

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

Verfasst: Freitag 22. Januar 2016, 20:06
von jens
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...

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

Verfasst: Freitag 22. Januar 2016, 20:31
von jens
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

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

Verfasst: Mittwoch 27. Januar 2016, 14:46
von jens
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: