2010-01-29 12 views
9

Ich habe ein Stück Code, mit dem ich nach den ausführbaren Dateien von Spieldateien suche und die Verzeichnisse zurückschicke. Ich würde gerne eine Art Fortschrittsanzeige darüber bekommen, wie weit os.walk ist. Wie würde ich so etwas erreichen?Wie bekommt man den Fortschritt von os.walk in Python?

Ich habe versucht, startpt = root.count(os.sep) und Abmessen davon, aber das gibt nur, wie tief os.walk ist in einem Verzeichnisbaum.

def locate(filelist, root=os.curdir): #Find a list of files, return directories. 
    for path, dirs, files in os.walk(os.path.abspath(root)): 
     for filename in returnMatches(filelist, [k.lower() for k in files]): 
      yield path + "\\" 
+0

die eigentliche Frage ist, warum dauert Ihr 'os.walk' so lange? Wie viele Dateien durchwühlst du? Was ist die Leistung der 'returnMatches'? – SilentGhost

+0

def returnMatches (a, b): Rückgabeliste (set (a) & set (b)) # Gibt eine Liste der Übereinstimmungen zwischen den angegebenen Listen zurück. , dass alle returnMatches ist, ist ... das dauert nur ein paar Sekunden dauern, aber ich hinzufüge, polieren, um das Programm so zu Menschen ist es nicht mein Programm aussieht nur ist nichts für ein paar Sekunden zu tun. Auf * MY * Maschine dauert das Ganze etwa 10 Sekunden. Aber das wird verpackt und läuft auf einer beliebigen Anzahl von Windows-Maschinen/Umgebungen – ThantiK

+0

Hinweis zu meinem Rechner: Immer noch ein sehr sehr langsames IDE-Laufwerk. ;) – ThantiK

Antwort

3

Ich habe das herausgefunden.

I verwendet os.listdir eine Liste der Top-Level-Verzeichnisse zu erhalten, und verwenden dann die .split Funktion auf dem Weg, der zurück os.walk, das erste Level-Verzeichnis zurückkehren, die es zur Zeit in war.

Die links ich mit einer Liste von Toplevel-Verzeichnissen, die ich den Index des aktuellen Verzeichnisses von os.walk finden konnte, und vergleichen Sie den Index mit der Länge der Liste zurückgegeben, geben Sie mir ein% abgeschlossen. ;)

Das gibt mir keinen glatten Fortschritt, weil das Niveau der Arbeit, die in jedem Verzeichnis getan wird, schwanken kann, aber das Glätten des Fortschrittsindikators ist für mich keine Sorge. Aber es könnte leicht erreicht werden, indem man den Pfad tiefer in die Verzeichnisstruktur einfügt.

Hier ist der endgültige Code von meinem Fortschritt bekommen:

def locateGameDirs(filelist, root=os.curdir): #Find a list of files, return directories. 
    toplevel = [folder for folder in os.listdir(root) if os.path.isdir(os.path.join(root, folder))] #List of top-level directories 
    fileset = set(filelist) 

    for path, dirs, files in os.walk(os.path.abspath(root)): 

     curdir = path.split('\\')[1] #The directory os.walk is currently in. 

     try: #Thrown here because there's a nonexistant(?) first entry. 
      youarehere = toplevel.index(curdir) 
      progress = int(((youarehere)/len(toplevel))*100) 
     except: 
      pass 

     for filename in returnMatches(filelist, [k.lower() for k in files]): 
      yield filename, path + "\\", progress 

Und jetzt zum Debuggen ich dies weiter im Code so mache:

for wow in locateGameDirs(["wow.exe", "firefox.exe", "vlc.exe"], "C:\\"): 
    print wow 

Gibt es eine nette kleine Art und Weise diesen Versuch/ausgenommen loswerden? es scheint, die erste Iteration des Pfades gibt mir nichts ...

+0

Die erste Iteration gibt Ihnen die Wurzel. Versuchen Sie, "Druckpfad" hinzuzufügen, um zu sehen, was ich meine. –

2

es in zwei Durchgängen durchführen: Erstens zählen, wie viele Gesamt Dateien/Ordner in dem Baum sind, und dann während des zweiten Durchgangs eigentliche Verarbeitung tun.

+0

Würde das nicht doppelt so lange dauern? –

+1

Das ist nur hilfreich, wenn die Verarbeitung wesentlich mehr Zeit in Anspruch nimmt als das Gehen des Baumes. Wenn das OP jede Datei öffnet, dann wahrscheinlich. Wenn das OP nur einige Details des Namens betrachtet, dann ist es fast sicher nicht. – Omnifarious

+0

@Onmifarious: Dann ist es nicht klar, warum er den Fortschritt wissen wollte, da es mehr kostet als die eigentliche Verarbeitung. – SilentGhost

0

Sie müssen die Gesamtanzahl der Dateien kennen, um einen aussagekräftigen Fortschrittsindikator zu erstellen.
Sie können die Anzahl der Dateien, wie diese

len(list(os.walk(os.path.abspath(root)))) 

bekommen, aber das wird einige Zeit in Anspruch nehmen, und Sie müssen wahrscheinlich eine Fortschrittsanzeige für die ...

Um die Anzahl der Dateien zu finden wirklich schnell Sie benötigen ein Dateisystem, das die Anzahl der Dateien für Sie festhält.

Vielleicht können Sie die Summe aus einem vorherigen Lauf speichern und verwenden, die als Schätzung

+1

Mir ist die Anzahl der Dateien egal. Ehrlich gesagt würde ich mich freuen, wenn ich nur weiß, in welchem ​​Top-Verzeichnis es sich befindet. Zum Beispiel habe ich Top-Verzeichnisse C genannt: \\ 1, C: \\ 2, und so weiter ... Nur zu sagen ‚Ihr auf Top-Level-Verzeichnis x aus x‘ wäre in Ordnung, ich einfach nicht wissen, wie man es schafft. – ThantiK

+0

arbeitete ich dies für mindestens mal meinen Top-Level-dirs bekommen: [Ordner für Ordner in os.listdir ('C: \\'), wenn os.path.isdir (os.path.join ("C: \\ ‘, Ordner))] Nun, wie würde ich darum, herauszufinden, zu gehen, wo os.walk ist? – ThantiK

5

Es hängt davon ab!

Wenn die Dateien und Verzeichnisse mehr oder weniger gleichmäßig verteilt sind, können Sie einen groben Prozess anzeigen, indem Sie annehmen, dass jedes Toplevel-Verzeichnis die gleiche Zeit benötigt. Aber wenn sie nicht gleichmäßig verteilt sind, können Sie es nicht billig herausfinden. Sie müssen entweder ungefähr wissen, wie jedes Verzeichnis im Voraus gefüllt ist, oder Sie müssen die gesamte Sache zweimal os.walk gehen (aber das ist nur nützlich, wenn Ihre tatsächliche Verarbeitung viel länger dauert als der os.walk selbst).

Das heißt: sagen Sie haben 4 Toplevel-Verzeichnisse, und jedes enthält 4 Dateien. Wenn Sie annehmen, dass jedes Toplevel-Verzeichnis 25% des Fortschritts einnimmt und jede Datei weitere 25% des Fortschritts für dieses Verzeichnis benötigt, können Sie eine nette Fortschrittsanzeige anzeigen. Aber wenn das letzte Unterverzeichnis viel mehr Dateien als die ersten enthält, wird Ihre Fortschrittsanzeige 75% erreichen, bevor Sie es herausfinden. Sie können das nicht wirklich beheben, wenn der os.walk selbst der Engpass ist (nicht Ihre Verarbeitung), und es ist ein beliebiger Verzeichnisbaum (nicht einer, bei dem Sie im Voraus wissen, wie lange jeder Teilbaum dauern wird).

Und natürlich, dass hier die Kosten unter der Annahme ist, ist ungefähr das Gleiche für jede Datei ...

4

nur einen unbestimmten Fortschrittsbalken zeigen (dh diejenigen, die einen Klecks zeigen Prellen hin und her oder der Magneto-Effekt) . Auf diese Weise wissen die Benutzer, dass das Programm etwas Nützliches tut, aber nicht in die Irre führt, was die Zeit bis zur Fertigstellung angeht.

+0

Auch wenn ich mein Problem herausgefunden habe, da die Operation so kurz ist, ist das wahrscheinlich richtig. Danke;) – ThantiK

0

Ich schlage vor, Sie vermeiden, das Verzeichnis zu gehen. Verwenden Sie stattdessen eine indexbasierte App zum schnellen Auffinden von Dateien. Sie können die Befehlszeilenschnittstelle der Anwendung über den Subprozess verwenden und die Dateien fast sofort finden.

Unter Windows siehe Everything. Unter UNIX suchen Sie nach Ort. Nicht sicher über den Mac, aber ich bin mir sicher, dass es auch eine Option gibt.

+0

Dies wird eine gepackte ausführbare Datei sein, die an Leute weitergegeben wird. Nicht für den persönlichen Gebrauch. Ich kann solche Dinge nicht benutzen. – ThantiK

+0

Konnten Sie die Such-App nicht einfach mit Ihrem Programm versenden? Möglicherweise von einem Installateur unterstützt? Wenn Sie wirklich gehen wollen, sind die einzigen Optionen, die ich sehe, bereits vorgeschlagen worden: zwei Spaziergänge (einen zum Zählen, einen für die eigentliche Operation) oder einen unbestimmten Fortschrittsbalken, den Sie nach jeder x Anzahl von Iterationen ankreuzen. –

+0

Nr Das Programm ist im Grunde nur eine 4mb ausführbare Datei mit py2exe verpackt, kein Grund, ein Programm zu installieren, die für eine Liste der installierten Spiele sucht gerade und lädt die Spiel-Dateien auf einem Server speichern. – ThantiK

0

Wie ich im Kommentar gesagt habe, liegt der Performance Flaschenhals wahrscheinlich außerhalb der locate Funktion. Ihre returnMatches ist eine ziemlich teure Funktion.Ich glaube, Sie besser dran seien es mit dem folgenden Code ersetzen:

def locate(filelist, root=os.curdir) 
    fileset = set(filelist)   # if possible, pass the set instead of the list as a first argument 
    for path, dirs, files in os.walk(os.path.abspath(root)): 
      if any(file.lower() in fileset for file in files): 
       yield path + '\\' 

diese Weise können Sie die Anzahl der verschwenderischen Operationen reduzieren, Ausbeute einmal pro Datei im Verzeichnis (was meiner Meinung nach ist das, was Sie tatsächlich eingerückt zu tun) und du kannst den Fortschritt zur gleichen Zeit vergessen. Ich glaube nicht, dass der Fortschritt sowieso ein erwartetes Merkmal der Schnittstelle wäre.

+0

def returnMatches (a, b): Rückgabeliste (Satz (a) & set (b)) Und ich versuchte, Ihre Methode hier gepostet. Es ging nicht schneller. – ThantiK

+0

@ThantiK: Es bedeutet nur, dass der Großteil der Zeit von "os.walk" selbst verbraucht wird. Es macht Ihren Ansatz nicht effizient. – SilentGhost

0

hier aus dem Kasten heraus denken ... was ist, wenn Sie es auf Größe basierend hat:

  • Verwenden subprocess 'du -sb' und erhalten die total_size Ihrer root ausführen Verzeichnis
  • Wie Sie gehen, überprüfen Sie die Größe der einzelnen Dateien und Abnahme von Ihrem total_size
  • pct_complete = (Sie remaining_size geben) (total_size - remaining_size)/total_size

Gedanken?

-aj

0

Eine Optimierung, die Sie tun könnten - Sie konvertieren Dateiliste in eine Menge bei jedem Aufruf von returnMatches, auch wenn es sich nie ändert. Verschieben Sie die Konvertierung an den Anfang der Funktion "locate" und übergeben Sie sie bei jeder Iteration.

+0

Danke - Ich nahm das tatsächlich von SilentGhosts Post, obwohl er sich mehr Sorgen um die Leistung machte als um die Aufgabe;) – ThantiK

0

Nun, das hat Spaß gemacht. Hier ist eine andere alberne Art, es zu tun, aber wie alles andere, berechnet es nur den richtigen Fortschritt für einheitliche Pfade.

import os, sys, time 

def calc_progress(progress, root, dirs): 
    prog_start, prog_end, prog_slice = 0.0, 1.0, 1.0 

    current_progress = 0.0 
    parent_path, current_name = os.path.split(root) 
    data = progress.get(parent_path) 
    if data: 
     prog_start, prog_end, subdirs = data 
     i = subdirs.index(current_name) 
     prog_slice = (prog_end - prog_start)/len(subdirs) 
     current_progress = prog_slice * i + prog_start 

     if i == (len(subdirs) - 1): 
      del progress[parent_path] 

    if dirs: 
     progress[root] = (current_progress, current_progress+prog_slice, dirs) 

    return current_progress 

def walk(start_root): 
    progress = {} 
    print 'Starting with {start_root}'.format(**locals()) 

    for root, dirs, files in os.walk(start_root): 
     print '{0}: {1:%}'.format(root[len(start_root)+1:], calc_progress(progress, root, dirs)) 
Verwandte Themen