Seite 1 von 1

os.walk(), liste mit realtiven pfaden zusammenstellen

Verfasst: Montag 4. Juni 2007, 09:18
von Zap
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

Verfasst: Montag 4. Juni 2007, 09:31
von BlackJack
Ich kann das Problem nicht nachvollziehen. Bei mir *sind* die Pfadangaben im Ergebnis Deiner Funktion relativ!?

Verfasst: Montag 4. Juni 2007, 09:39
von Zap
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.

Verfasst: Montag 4. Juni 2007, 09:52
von Zap
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.

Verfasst: Montag 4. Juni 2007, 10:44
von 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'

Verfasst: Montag 4. Juni 2007, 10:46
von Zap
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'

Verfasst: Montag 4. Juni 2007, 11:05
von 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

Verfasst: Montag 4. Juni 2007, 11:42
von Zap
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)

Verfasst: Montag 4. Juni 2007, 12:51
von 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.

Verfasst: Montag 4. Juni 2007, 12:59
von Y0Gi
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.

Verfasst: Montag 4. Juni 2007, 13:24
von Zap
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.