Größte und neuste Datei aus Verzeichnis?

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.
RedSharky
User
Beiträge: 99
Registriert: Donnerstag 13. April 2006, 15:38

Größte und neuste Datei aus Verzeichnis?

Beitragvon RedSharky » Sonntag 20. Juli 2008, 22:51

Hi,
ich habe mir den Kopf zermartert, stehe aber irgendwie auf dem Schlauch.

Ich möchte mir lediglich zwei Funktionen schreiben, die mir sagen, welches die größte oder welches die neuste Datei in einem Verzeichnis ist.

Das muss doch irgendwie über os gehen. Und dann irgendwie sortiert werden.
Das Problem ist, dass man zwar leicht nach z. B. der Dateigröße sortieren kann, aber dann nicht weiß, wie der Dateiname dazu ist.
Irgendwas mit Dictionary?

Habe mal etwas sinnfreien Code erzeugt:

Code: Alles auswählen

from os import *

dirpath = "C:/temp"

class CacheFile:
    def __init__(self,n,s,t):    #constructor method
        self.name = n
        self.size = s
        self.time = t

chdir(dirpath) #changes working directory
print getcwd() #print current dir
print

cache_files = listdir(dirpath) #list all files in current directory
print cache_files
print

cf = []
for i in xrange(len(cache_files)):
    cf.append(i)
print cf
print

#make class objects
for i in xrange(len(cf)):
    cf[i] = CacheFile(cache_files[i],stat(cache_files[i])[6],stat(cache_files[i])[8])

#output
for i in xrange(len(cf)):
    print cf[i].name, cf[i].size, cf[i].time
print

#sort a list
sizelist = []
for i in xrange(len(cf)):
     sizelist.append(cf[i].size)
print sizelist
print   

sizelist.sort()
print sizelist
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Sonntag 20. Juli 2008, 23:21

Wozu Klassen?

Code: Alles auswählen

import os, operator
files = os.listdir('.')
stats = [os.stat(f) for f in files]
ctimes = [stat.st_ctime for stat in stats]
sizes = [stat.st_size for stat in stats]
combined = zip(files, ctimes, sizes)
# newest file
print reversed(sorted(combined, key=operator.itemgetter(1))).next()
# largest file
print reversed(sorted(combined, key=operator.itemgetter(2))).next()
My god, it's full of CARs! | Leonidasvoice vs Modvoice
BlackJack

Beitragvon BlackJack » Sonntag 20. Juli 2008, 23:36

Ein bisschen umständlich. Sowohl `list.sort()`, als auch `sorted()` kennen das Argument `reverse` und ab Python 2.5 (inklusive) kann man sich das sortieren sparen, weil `min()` und `max()` dann auch das `key`-Argument kennen und einfach linear das Gewünschte suchen.
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

Beitragvon veers » Sonntag 20. Juli 2008, 23:54

Leonidas hat geschrieben:Wozu Klassen?
Weil named tuples erst mit 2.6 kommen?
My Website - 29a.ch
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
Benutzeravatar
snafu
User
Beiträge: 5389
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Beitragvon snafu » Montag 21. Juli 2008, 00:06

veers hat geschrieben:
Leonidas hat geschrieben:Wozu Klassen?
Weil named tuples erst mit 2.6 kommen?


Ich glaube, Leonidas wollte damit eher seinen alternativen Lösungsvorschlag kommentieren, der eben ohne Klassen auskommt.
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Montag 21. Juli 2008, 00:29

Vereinfacht. Tatsächlich habe ich ``min()`` und ``max()`` vergessen gehabt. Aber gut zu wissen, dass die auch ein ``key``-Argument haben.

Code: Alles auswählen

import os, operator
files = os.listdir('.')
stats = [os.stat(f) for f in files]
ctimes = [stat.st_ctime for stat in stats]
sizes = [stat.st_size for stat in stats]
combined = zip(files, ctimes, sizes)
# newest file
print max(combined, key=operator.itemgetter(1))
# largest file
print max(combined, key=operator.itemgetter(2))
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

Beitragvon veers » Montag 21. Juli 2008, 07:23

snafu hat geschrieben:
veers hat geschrieben:
Leonidas hat geschrieben:Wozu Klassen?
Weil named tuples erst mit 2.6 kommen?


Ich glaube, Leonidas wollte damit eher seinen alternativen Lösungsvorschlag kommentieren, der eben ohne Klassen auskommt.
Ja, an Stelle derer Verwendet er Tuples und Magic Numbers:

Code: Alles auswählen

key=operator.itemgetter(1)


Leonidas, warum
stats = [os.stat(f) for f in files] und nicht stats = map(os.stat, files)?
My Website - 29a.ch

"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
BlackJack

Beitragvon BlackJack » Montag 21. Juli 2008, 10:35

Ich will auch mal:

Code: Alles auswählen

import os
from functools import partial
from itertools import imap

def main():
    filenames = os.listdir('.')
    tmp = zip(filenames, imap(os.stat, filenames))
   
    def key_func(attr_name, (filename, stats)):
        return getattr(stats, attr_name)
   
    for stat_attr in ('st_ctime', 'st_size'):
        print max(tmp, key=partial(key_func, stat_attr))


Und noch mal mit den `path` Modul:

Code: Alles auswählen

from path import path

def methodcaller(method_name, *args, **kwargs):
    return lambda o: getattr(o, method_name)(*args, **kwargs)

def main():
    files = path('.').listdir()
    for method_name in ('getctime', 'getsize'):
        print max(files, key=methodcaller(method_name))
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Montag 21. Juli 2008, 12:00

veers hat geschrieben:Ja, an Stelle derer Verwendet er Tuples und Magic Numbers:

Code: Alles auswählen

key=operator.itemgetter(1)

So magisch finde ich es nicht, ist ja schließlich nur ein Indexzugriff. Wenn ich 1 und 2 in Konstanten auslagere würde es auch gehen aber die Lesbarkeit kaum verbessern.

veers hat geschrieben:Leonidas, warum
stats = [os.stat(f) for f in files] und nicht stats = map(os.stat, files)?

Ist als LC warscheinlich schneller.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Beitragvon audax » Montag 21. Juli 2008, 12:05

Code: Alles auswählen

% python -mtimeit "import os; files = os.listdir('.'); [os.stat(f) for f in files]"
1000 loops, best of 3: 602 usec per loop
% python -mtimeit "import os; files = os.listdir('.'); map(os.stat, files)"       
1000 loops, best of 3: 554 usec per loop

Natürlich ist das wieder der Beste von 10 Läufen, es ist also alles im Cache.

Code: Alles auswählen

 % python -mtimeit "map(int, range(10))"                                   
100000 loops, best of 3: 3.79 usec per loop
% python -mtimeit "[int(n) for n in range(10)]"
100000 loops, best of 3: 5.11 usec per loop

Und hier nochmal, mit möglichst wenig overhead.

map > LC ;)
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Montag 21. Juli 2008, 12:21

audax hat geschrieben:map > LC ;)

Und jetzt die Erklärung?
My god, it's full of CARs! | Leonidasvoice vs Modvoice
lunar

Beitragvon lunar » Montag 21. Juli 2008, 12:32

os.listdir liefert relative Pfade, man muss also os.path.join einschalten:

Code: Alles auswählen

def largest_file(directory):
    files = (os.path.join(directory, f) for f in os.listdir(directory))
    return max(((f, os.path.getsize(f)) for f in files if os.path.isfile(f)),
               key=operator.itemgetter(1))

Und für die neueste Datei:

Code: Alles auswählen

def newest_file(directory):
    files = (os.path.join(directory, f) for f in os.listdir(directory))
    return max(((f, os.path.getmtime(f)) for f in files if os.path.isfile(f)),
               key=operator.itemgetter(1))
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Beitragvon audax » Montag 21. Juli 2008, 12:58

Leonidas hat geschrieben:
audax hat geschrieben:map > LC ;)

Und jetzt die Erklärung?

hmm?
Man sollte map() nicht krampfhaft durch LC ersetzen, vor allem nicht aus performance-Gründen.
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Montag 21. Juli 2008, 13:04

audax hat geschrieben:
Leonidas hat geschrieben:
audax hat geschrieben:map > LC ;)

Und jetzt die Erklärung?

hmm?

Naja, schließlich haben wir bei ``map()`` genauso viele Aufrufe der inneren Funktion (``os.stat()``) und noch dazu den ``map()`` Aufruf. Der ist auch nicht so billig, da man die Funktion erst im Namensraum finden muss und dann ausführen muss. Intern muss genauso wie bei einer LC über die Werte iteriert werden von daher würde ich gerne wissen, warum ``map()`` dennoch schneller ist.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Beitragvon audax » Montag 21. Juli 2008, 13:15

Code: Alles auswählen

  4           0 BUILD_LIST               0
              3 DUP_TOP             
              4 STORE_FAST               0 (_[1])
              7 LOAD_GLOBAL              0 (range)
             10 LOAD_CONST               1 (10)
             13 CALL_FUNCTION            1
             16 GET_ITER           
        >>   17 FOR_ITER                19 (to 39)
             20 STORE_FAST               1 (n)
             23 LOAD_FAST                0 (_[1])
             26 LOAD_GLOBAL              1 (int)
             29 LOAD_FAST                1 (n)
             32 CALL_FUNCTION            1
             35 LIST_APPEND         
             36 JUMP_ABSOLUTE           17
        >>   39 DELETE_FAST              0 (_[1])
             42 POP_TOP             
             43 LOAD_CONST               0 (None)
             46 RETURN_VALUE       

Das ist die LC.

Code: Alles auswählen

  7           0 LOAD_GLOBAL              0 (map)
              3 LOAD_GLOBAL              1 (int)
              6 LOAD_GLOBAL              2 (range)
              9 LOAD_CONST               1 (10)
             12 CALL_FUNCTION            1
             15 CALL_FUNCTION            2
             18 POP_TOP             
             19 LOAD_CONST               0 (None)
             22 RETURN_VALUE 

Und das mit map.

Bei einer LC findet wohl das Bilden der Liste komplett in Python statt, bei map() in C, das macht wohl den kleinen unterschied aus.

btw, der Code:

Code: Alles auswählen

import dis

def f():
    [int(n) for n in range(10)]

def g():
    map(int, range(10))

dis.dis(f)

dis.dis(g)


Und auch bei einer LC muss die Liste nachgeschlagne werden:

Code: Alles auswählen

             23 LOAD_FAST                0 (_[1])

Wer ist online?

Mitglieder in diesem Forum: Don Terremoto