os.walk(), liste mit realtiven pfaden zusammenstellen

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
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Hallo zusammen, ich habe eigentlich kein großes Problem,
suche aber eine effiziente Lösung auf die ich einfach nicht komme.
( Bzw. nichts standardmäßiges dazu finde )

Und zwar möchte ich per os.walk() eine Liste mit allen Dateien zusammenstellen, allerdings sollen die Pfadangaben realtiv sein.

Code: Alles auswählen

def my_walk(rootDir):
    filelist = list()
    for dirname,dirs,filenames in os.walk(rootDir): 
      for filename in filenames: 
        filelist.append(os.path.join(dirname,filename)) 
    return filelist
Ich hab's mit split-Operationen mit rootDir versucht, aber das gefiehl mit nicht so richtig. Gibt es ne Möglichkeit das elegant mit pythonmitteln zu machen? Vielleicht direkt auf Basis anderer Elemente zu joinen ?

Vielen Dank im vorraus
BlackJack

Ich kann das Problem nicht nachvollziehen. Bei mir *sind* die Pfadangaben im Ergebnis Deiner Funktion relativ!?
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Bei mir nich :(

Code: Alles auswählen

>>> l = my_walk(os.getcwd())
>>> l
['H:\\FirmwarePackage.xml', 'H:\\list-test.py', 'H:\\notebook.cfg', 'H:\\upload_fwp.py', '
H:\\.idlerc\\breakpoints.lst', 'H:\\.idlerc\\config-main.cfg', 'H:\\.idlerc\\recent-files.
lst']
>>>
Problem an der Stelle ist das ich mit rootDir halt nen Absoluten Pfad übegeben muss. Ich könnte natürlich mit chdir() in das entsprechende Verzeichnis springen und wieder zurück, finde ich aber auch nicht allzu schick.
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Ok, hat sich erledigt

Code: Alles auswählen

>>> c = os.getcwd()
>>> [ f.lstrip(c) for f in l]
['FirmwarePackage.xml', 'list-test.py', 'notebook.cfg', 'upload_fwp.py', '.idlerc\\breakpo
ints.lst', '.idlerc\\config-main.cfg', '.idlerc\\recent-files.lst']
Werde das vor dem join noch in die Funktion einbauen.
BlackJack

Lies Dir nochmal die Doku zu `lstrip()` durch. Das Argument ist eine Menge von Zeichen und kein Präfix.

Code: Alles auswählen

In [22]: c = 'H:\\'

In [23]: f = 'H:\\Hallo.txt'

In [24]: f.lstrip(c)
Out[24]: 'allo.txt'

In [25]: c = 'H:\\langweilige texte im ordner\\'

In [26]: f.lstrip(c)
Out[26]: '.txt'
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Aua... danke, das wäre böse gewesen.
Kannte das Verhalten, aber da hab ich garnicht mehr dran gedacht.
Was schlägst vor, doch os.path.split() ?

Edit: Ups, ich meinte natürlich split() auf den string, nicht mit os..

Code: Alles auswählen

>>> l[0]
'H:\\FirmwarePackage.xml'
>>> l[0].split(c)
['', 'FirmwarePackage.xml']
>>> l[0].split(c)[1]
'FirmwarePackage.xml'
BlackJack

Wenn Du schon einen absoluten Pfad angibst, dann ist ja erst einmal die Frage wozu das Ergebnis denn relativ sein soll? Zum aktuellen Arbeitsverzeichnis? Das wird hässlich wenn der absolute Pfad für die Funktion nicht unterhalb des Arbeitsverzeichnisses liegt.

Schnell runtergehackt und nahezu ungetestet:

Code: Alles auswählen

def walk(path):
    absolute_path = os.path.abspath(path)
    current_working_directory = os.getcwd()
    if not absolute_path.startswith(current_working_directory):
        raise ValueError('path must be under current working directory')
    filelist = list()
    for dirname, dirs, filenames in os.walk(absolute_path):
        for filename in filenames:
            filename = os.path.abspath(os.path.join(dirname, filename))
            assert filename.startswith(absolute_path)
            filelist.append(filename[len(current_working_directory) + 1:])
    return filelist
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

BlackJack hat geschrieben:Wenn Du schon einen absoluten Pfad angibst, dann ist ja erst einmal die Frage wozu das Ergebnis denn relativ sein soll? Zum aktuellen Arbeitsverzeichnis?
Nene, hat nichts mitm Arbeitsverzeichnis zu tun. Das ist für einen Abgleich gedacht zwischen Server und Client, die in unterschiedlichen Rootverzeichnissen gleiche Ordnerstrukturen beherbergen.
Es ist somit also "uninteressant" wo das Arbeitsverzeichnis ist, wenn eine
Eingabe keinen Sinn macht, dann melde ich das.

Deine Lösung mit dem zählen der Zeichen finde ich nicht so prickelnd.
BlackJack hat geschrieben:

Code: Alles auswählen

filelist.append(filename[len(current_working_directory) + 1:])
Hat die irgendwelche Vorteile gegenüber meinem split() ?

Zur Zeit sieht meine Lösung so aus:

Code: Alles auswählen

def walk(rootDir):
    filelist = list()
    # if rootDir is "." or ".." we need the abspath to split correct
    rootDir = os.path.abspath(rootDir)
    assert os.path.isdir(rootDir), "Unknown path:'%s'" % rootDir     
    for dirname,dirs,filenames in os.walk(rootDir): 
        # get relative path to rootDir
        subDir = dirname.split(rootDir)[1]
        for filename in filenames: 
            filelist.append(os.path.join(subDir,filename)) 
    return filelist
(Bin immer für Verbesserungen offen)
BlackJack

Also ich finde die `split()`-Lösung unschön. Beim "Zeichenzählen" weiss man wenigstens genau was da passiert. Es werden nicht wirklich Zeichen gezählt, die Anzahl ist bekannt. Das drückt ziemlich direkt aus, dass man am Anfang etwas mit der Länge des Präfixes entfernt.

Beim `split()` muss man erst einmal überlegen was `rootDir` eigentlich ist und das dieses `split()` immer zwei Elemente als Ergebnis hat ─ ups, *hat* es das *immer*!? Allgemein sehe ich keinen Grund warum `rootDir` nicht mehrfach als Teilword in `dirname` vorkommen kann. Dann funktioniert der Code nicht mehr.

Vom Aufwand her ist es auch einfacher die Länge abzufragen und eine neue Zeichenkette zu erzeugen, als mit `split()` eine Zeichenkette in einer anderen suchen zu lassen, dabei eine Liste mit mindestens zwei neuen Zeichenketten zu erzeugen, von denen man nur an einer interessiert ist.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Wenn du nur den eigentlichen Verzeichnisnamen willst, nimm doch ``os.path.split(foo)[-1]``. Und schau dir auch mal ``os.path.basename`` und ``os.path.dirname`` an, vielleicht bringen die dich jetzt oder später mal weiter - sind dir vermutlich noch nicht bekannt.
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

BlackJack hat geschrieben:Beim `split()` muss man erst einmal überlegen was `rootDir` eigentlich ist und das dieses `split()` immer zwei Elemente als Ergebnis hat ─ ups, *hat* es das *immer*!? Allgemein sehe ich keinen Grund warum `rootDir` nicht mehrfach als Teilword in `dirname` vorkommen kann. Dann funktioniert der Code nicht mehr.
Ok das ist ein Argument. Dann werde ich das so übernehmen, danke ;)
Y0Gi hat geschrieben:Wenn du nur den eigentlichen Verzeichnisnamen willst, nimm doch ``os.path.split(foo)[-1]``. Und schau dir auch mal ``os.path.basename`` und ``os.path.dirname`` an, vielleicht bringen die dich jetzt oder später mal weiter - sind dir vermutlich noch nicht bekannt.
Danke, kenne ich alle, bringen mir an der Stelle aber nichts.
Antworten