2009-05-07 6 views
9

Ich schreibe ein Python-Backup-Skript und ich muss die älteste Datei in einem Verzeichnis (und seine Unterverzeichnisse) finden. Ich muss es auch nur in * .avi Dateien filtern.Finden Sie die älteste Datei (rekursiv) in einem Verzeichnis

Das Skript wird immer auf einem Linux-Rechner ausgeführt. Gibt es eine Möglichkeit, dies in Python zu tun, oder wären einige Shell-Befehle besser?

Im Moment bin ich ausgeführt, um den freien Speicherplatz auf einer bestimmten Partition zu erhalten, und wenn es weniger als 5 Gigabyte frei ist, möchte ich die ältesten *.avi Dateien löschen, bis diese Bedingung erfüllt ist.

+1

Warte, wie verwendest du du, um freien Speicherplatz zu bekommen? Das sagt nur Verwendung AFAIK. –

+0

Sorry, gemeint ist nicht du. –

+1

Bist du sicher, dass es nicht df ist? : P –

Antwort

21

Hm. Nadias Antwort ist näher an dem, was Sie zu fragen; jedoch in einem Baum die (einzige) älteste Datei für die Suche, versuchen Sie dies:

import os 
def oldest_file_in_tree(rootfolder, extension=".avi"): 
    return min(
     (os.path.join(dirname, filename) 
     for dirname, dirnames, filenames in os.walk(rootfolder) 
     for filename in filenames 
     if filename.endswith(extension)), 
     key=lambda fn: os.stat(fn).st_mtime) 

Mit einer wenig Änderung, können Sie die n ältesten Dateien (ähnlich Nadia Antwort) erhalten:

import os, heapq 
def oldest_files_in_tree(rootfolder, count=1, extension=".avi"): 
    return heapq.nsmallest(count, 
     (os.path.join(dirname, filename) 
     for dirname, dirnames, filenames in os.walk(rootfolder) 
     for filename in filenames 
     if filename.endswith(extension)), 
     key=lambda fn: os.stat(fn).st_mtime) 

beachten Sie, dass die .endswith Methode ermöglicht Anrufe als:

oldest_files_in_tree("/home/user", 20, (".avi", ".mov")) 

auf mehr als eine Erweiterung auswählen.

Schließlich sollten Sie die vollständige Liste der Dateien, nach Änderungszeit bestellt wollen, um so viele zu löschen, um Speicherplatz freizugeben erforderlich, hier ist etwas Code:

import os 
def files_to_delete(rootfolder, extension=".avi"): 
    return sorted(
     (os.path.join(dirname, filename) 
     for dirname, dirnames, filenames in os.walk(rootfolder) 
     for filename in filenames 
     if filename.endswith(extension)), 
     key=lambda fn: os.stat(fn).st_mtime), 
     reverse=True) 

und beachten Sie, dass die reverse=True das bringt ältesten Dateien am Ende der Liste, so dass für die nächste Datei zu löschen, tun Sie einfach eine file_list.pop().

By the way, für eine komplette Lösung für Ihr Problem, da Sie unter Linux ausgeführt werden, wo die os.statvfs verfügbar ist, können Sie tun:

import os 
def free_space_up_to(free_bytes_required, rootfolder, extension=".avi"): 
    file_list= files_to_delete(rootfolder, extension) 
    while file_list: 
     statv= os.statvfs(rootfolder) 
     if statv.f_bfree*statv.f_bsize >= free_bytes_required: 
      break 
     os.remove(file_list.pop()) 

statvfs.f_bfree die freien Blöcke Gerät sind und statvfs.f_bsize ist die Block Größe. Wir nehmen die rootfolder Statvfs, also beachten Sie symbolische Links, die auf andere Geräte zeigen, wo wir viele Dateien löschen könnten, ohne tatsächlich Speicherplatz auf diesem Gerät freizugeben.

UPDATE (Kopieren Kommentar von Juan):

auf das Betriebssystem und Dateisystem-Implementierung abhängig, können Sie f_bfree von f_frsize vermehren wollen, anstatt f_bsize. In einigen Implementierungen ist letzteres die bevorzugte Größe der E/A-Anfrage. Zum Beispiel auf einem System FreeBSD 9 ich gerade getestet, war f_frsize 4096 und f_bsize war 16384. POSIX sagt der Blockanzahl Felder „in Einheiten von f_frsize“ sind (siehe http://pubs.opengroup.org/onlinepubs/9699919799//basedefs/sys_statvfs.h.html)

+1

Abhängig von der Betriebssystem- und Dateisystemimplementierung können Sie 'f_bfree' mit' f_frsize' anstatt mit 'f_bsize' multiplizieren. In einigen Implementierungen ist letzteres die bevorzugte Größe der E/A-Anfrage.Auf einem FreeBSD 9-System, das ich gerade getestet habe, war "f_frsize" 4096 und "f_bsize" war 16384. POSIX sagt, dass die Blockanzahl Felder "in Einheiten von f_frsize" sind - http://pubs.opengroup.org/onlinepubs/ 9699919799 // basedefs/sys_statvfs.h.html – Juan

+0

@Juan vielen Dank! – tzot

2

Überprüfen Sie den Linux-Befehl find.

Alternativ können Sie mithilfe von this post ls und tail zusammenführen, um die älteste Datei in einem Verzeichnis zu löschen. Dies könnte in einer Schleife erfolgen, während nicht genügend freier Speicherplatz vorhanden ist.

als Referenz, hier ist der Shell-Code, der es tut (den Link für weitere Alternativen folgen und eine Diskussion):

ls -t -r -1 /path/to/files | head --lines 1 | xargs rm 
13

Um es in Python zu tun, können Sie os.walk(path) verwenden rekursiv über die Dateien zu durchlaufen, und die st_size und st_mtime Attribute von os.stat(filename), um die Dateigrößen und Änderungszeiten zu erhalten.

10

können Sie stat und fnmatch Module verwenden gemeinsam die Dateien Zeit

st_mtime refere zur letzten Änderung zu finden. Sie können einen anderen Wert wählen, wenn Sie wollen

import os, stat, fnmatch 
file_list = [] 
for filename in os.listdir('.'): 
    if fnmatch.fnmatch(filename, '*.avi'): 
     file_list.append((os.stat(filename)[stat.ST_MTIME], filename)) 

Dann können Sie die Liste nach Zeit bestellen und löschen Sie danach.

file_list.sort(key=lambda a: a[0]) 
0

Die os module bietet die Funktionen, die Sie benötigen Verzeichnislisten zu erhalten und Informationen in Python-Datei. Ich habe os.walk gefunden, um besonders nützlich zu sein, um Verzeichnisse rekursiv zu gehen, und os.stat gibt Ihnen ausführliche Informationen (einschließlich Änderungszeit) auf jedem Eintrag.

Sie können dies möglicherweise einfacher mit einem einfachen Shell-Befehl tun. Ob das für Sie besser ist oder nicht, hängt davon ab, was Sie mit den Ergebnissen machen wollen.

7

Ich denke, der einfachste Weg, dies zu tun wäre, zu finden zusammen mit ls-t (Dateien nach Zeit sortieren).

etwas in dieser Richtung sollte es tun (löscht älteste AVI-Datei unter bestimmten Verzeichnis)

find/-name "*.avi" | xargs ls -t | tail -n 1 | xargs rm 

Schritt für Schritt ....

find/-name "* .avi" - Finden Sie alle avi-Dateien rekursiv beginnend im Wurzelverzeichnis

xargs ls -t - Alle Dateien nach Änderungsdatum sortieren, vom neuesten zum ältesten.

tail -n 1 - die letzte Datei in der Liste greifen (älteste)

Xargs rm - und abnehmen

+0

Er erwähnt das Laufen in einer Schleife. Da 'find' tendenziell eine teure Operation ist, ist es wahrscheinlich eine bessere Idee, die Ergebnisse von' xargs ls' herumzuhalten (vielleicht in einer Array-Variablen) und Dateinamen daraus einzeln zu ziehen. –

+0

Vielleicht ersetzen finden mit locate und grep? –

2

Hier ist eine andere Python-Formulierung, die ein bisschen alt -School im Vergleich zu anderen, aber ist leicht zu ändern, und behandelt den Fall, dass keine übereinstimmenden Dateien ohne eine Ausnahme auslösen.

import os 

def find_oldest_file(dirname="..", extension=".avi"): 
    oldest_file, oldest_time = None, None 
    for dirpath, dirs, files in os.walk(dirname): 
     for filename in files: 
      file_path = os.path.join(dirpath, filename) 
      file_time = os.stat(file_path).st_mtime 
       if file_path.endswith(extension) and (file_time<oldest_time or oldest_time is None): 
       oldest_file, oldest_time = file_path, file_time 
    return oldest_file, oldest_time 

print find_oldest_file() 
Verwandte Themen