diskusage

Code-Stücke können hier veröffentlicht werden.
Antworten
Benutzeravatar
knekke
User
Beiträge: 100
Registriert: Freitag 29. Oktober 2004, 17:23
Wohnort: Schweden

Hallo beisammen,
aus Spaß an der Freud, zu Übungszwecken, und weil es unter Windows den bash-Befehl "du" nicht gibt, hab ich hier mal was kleines zusammengeschustert. Das Script listet die Größe eines Ordners, sowie der enthaltenen Unterordner (nur die erste Ebene) und Dateien. Ausserdem zeigt es noch wieviele Dateien und Verzeichnisse sich direkt in den Unterordnern befinden (braucht ausser einer Arbeitskollegin von mir wohl kein normalsterblicher :wink: ).
Da ich in meinem Bekanntenkreis der Einzige bin der seine Freizeit mit sowas zubringt, würde mich doch die eine oder andere Meinung von Euch dazu Interessieren. Vieleicht ließe sich das ganze ja in einem 3-Zeiler realisieren, und ich hab einfach um 28 Ecken zuviel gedacht.... :shock:
Also Kommentare immer gerne (aber nicht zu den Variablennamen (auch wenn sie eine Schmähung verdient hätten)... die sind z.T. aus Tippfehlern entstanden, die ich dann einfach fortgeführt hab :roll: )....
Los gehts:

Code: Alles auswählen

#!/usr/bin/python

import os
from os.path import join, getsize
 
path = raw_input("Verzeichnis (e.g. /home): ")
    
def getsizes(path):
    bytes=[]
    allsizes = []
    filse = []
    dirse = []
    content = os.listdir(path)      # inhalt von path
    os.chdir(path)
    for a in range(0,len(content)): # checken ob dir oder file
        if os.path.isdir(content[a]): 
            dirse.append(content[a])
        elif os.path.isfile(content[a]):
            filse.append(content[a])
        else:
            break
    filse.sort()
    dirse.sort()
    print ""
    print ""
    print "size		type dirs/files	name"
    print "::::::::::::::::::::::::::::::::::::::::::::"
##############################################
#####   FOLDERS    ################
    for i in range(0,len(dirse)):
        u = dirse[i]
        subpath = join(path, u)
        tmpbytes =[]
        tmpdirs = []
        tmpfiles = []
        for paths, dirs, files in os.walk(subpath):    
            
            tmpfiles.append(files)
            tmpdirs.append(dirs)
            for name in files:
                datei = join(paths, name)
                if os.path.isfile(datei):
                    size = getsize(datei)
                    tmpbytes.append(size)
        x = (sum(tmpbytes)/1024)/1024.0
        allsizes.append(x)
        a,b = len(tmpfiles[0]),len(tmpdirs[0])
        print "%.3f" % x, 'MB	DIR  ',b,"/",a,"	",u
    print '---'
##############################################
#####   FILES    ################
    for as in range(0,len(filse)):
        datei = join(path, filse[as])
        filebytes = []
        if os.path.isfile(datei):
            filesize = getsize(datei)
            filebytes.append(filesize)
        x = (sum(filebytes)/1024)/1024.0
        allsizes.append(x)
        print "%.3f" %x, 'MB	file	',filse[as]
    print '---'
    mastersize = sum(allsizes)
    print path, "%.2f" %mastersize, "MB"

getsizes(path)
ab und an ist das script mal abgeschmiert (kann ich gerade leider nicht reproduzieren, könnte aber sein, daß das was mit Berechtigungen zutun hatte...)
Viel Spaß, danke und bis später,
Thomas
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

Hi!

Hab's mir noch nicht genau angesehen, aber hast Du nicht kürzlich gesagt dass Du bei range die 0 weglässt? :)

Gruß, mawe
Benutzeravatar
knekke
User
Beiträge: 100
Registriert: Freitag 29. Oktober 2004, 17:23
Wohnort: Schweden

Mach ich auch, aber das Script is schon ne Woche alt 8)
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

Hi!

Kein 3-Zeiler, aber etwas kürzer :wink: (wem's bekannt vorkommt, es ist aus dem Tutorial, leicht geändert)

Code: Alles auswählen

import os
from os.path import join, getsize

def collect(path):
    total = 0
    for root, dirs, files in os.walk(path):
        print root
        s = sum([getsize(join(root,name)) for name in files])
        print "%i bytes in %i files" % (s,len(files))
        total += s
    print "Total: ", total

path = raw_input("Pfad: ")
collect(path)
Gruß, mawe
Benutzeravatar
knekke
User
Beiträge: 100
Registriert: Freitag 29. Oktober 2004, 17:23
Wohnort: Schweden

Das kenn ich!!! Aber den (oder heisst es das??) Output von diesem Ding kann man doch niemandem zumuten, oder?
Meine Intention ist ja "du --max-depth 1" in etwa nachzubauen, d.h. sich nur die first-level (oder wie auch immmer) Unterverzeichnisse anzeigen zu lassen. Und da würde ich gerne wissen, ob mein weg ok ist (die nullen in range lass ich weg und ich sollte evtl. enumerate() verwenden), oder ob den etwas erfahreneren Python-benutzern ein kalter Schauer über den Rücken läuft, wenn Sie das sehen... :?:
BlackJack

Du solltest weder (x)range() noch enumerate() verwenden sondern gleich über die Sequenzen iterieren. Du brauchst den Index doch gar nicht.

Und ich persönlich finde es nicht so schön (x)range in Schleifen zu verwenden. Das macht den Code nur unnötig kompliziert weil man eine Variable mehr im Schleifenrumpf hat.
Benutzeravatar
knekke
User
Beiträge: 100
Registriert: Freitag 29. Oktober 2004, 17:23
Wohnort: Schweden

Guter Punkt.... wird gemacht!
BlackJack

Nochmal Kritik :twisted:

Das mit dem iterieren über die gewünschte Sequenz statt Zugriff über Index schrob ich ja schon.

Code: Alles auswählen

for i in range(0,len(dirse)):
    u = dirse[i]
    # ...

# =>

for dir in dirs:
    # ...
Damit sparst Du schonmal ein paar von Deinen 25 lokalen Variablen. Die Funktion ist ein wenig lang und unübersichtlich. Bis auf Variablennamen haben die beiden Abschnitte mit den 'FOLDER' und 'FILES' Kommentaren sehr viel identischen Quelltext. Und Namen wie a, b, u und x können sehr "nichtssagend" sein. Einen Namen wirst Du übrigens problemlos los: `bytes` ganz am Anfang der Funktion. Die Liste wird nämlich nirgends benutzt. Und zu dem konsequent durchgehaltenen "Vertippern": Die meisten Editoren haben eine Suchen/Ersetzen Funktion. ;-)

Hier ist das ganze mal in handlichere Unterfunktionen aufgeteilt::

Code: Alles auswählen

#!/usr/bin/env python
from __future__ import division
import os, sys, math
from os.path import getsize, isdir, isfile, islink, join
from itertools import chain, ifilterfalse, imap


def format_bytesize(size, precision=1):
    """Fomats a `size` in bytes as string with a unit attached.
    
    The unit is one of 'B', 'KiB', 'MiB', 'GiB', and 'TiB'.  The number is
    formatted so that it has the smallest possible unit but not more than 3
    digits before the decimal point.  Unless it's more then 999 terabytes
    of course.
    
    How many digits are placed after the decimal point depends on the
    `precision` parameter.  If the `size` can be formatted as bytes there's no
    fractional part at all.
    
    :raises ValueError: if `size` is negative.
    """
    if size < 0:
        raise ValueError('negative size (%r)' % size)
    # 
    # (Short) Names for 1024 based data size units:  Bytes, KibiBytes,
    # MebiBytes, ...
    # 
    # TODO: Note down reference to ISO/IEC standard here.
    # 
    unit_names = ('B', 'KiB', 'MiB', 'GiB', 'TiB')
    # 
    # As long as there are more than 3 digits in the integer part of the size
    # and there is a higher unit, divide `size` by 1024.
    # 
    power = 0
    while size and math.log10(size) >= 3 and power < len(unit_names):
        power += 1
        size /= 1024
    # 
    # A size given in bytes does not have a fractional part.
    # 
    if power == 0:
        number_format = '%d'
    else:
        number_format = '%%.%df' % precision
    
    return (number_format + ' %-3s') % (size, unit_names[power])


def dir_and_filenames(path):
    """Collects all directory names and file names plus file sizes found at
    given `path` (non-recursive).
    
    Both sequences are sorted by name.
    
    Symbolic links are ignored to prevent special cases like dead links.
    
    :returns: a tuple of directory names and file names plus file sizes.
    :rtype: ([str], [(str, int)])
    """
    dirnames = list()
    filenames_and_sizes = list()
    for name in os.listdir(path):
        fullname = join(path, name)
        if not islink(fullname):
            if isdir(fullname):
                dirnames.append(name)
            elif isfile(fullname):
                filenames_and_sizes.append((name, getsize(fullname)))
    dirnames.sort()
    filenames_and_sizes.sort()
    return (dirnames, filenames_and_sizes)


def dir_statistic(path):
    """Counts all files, subdirectories and their total size untder given
    `path` recursivly.
    
    Symbolic links to files and directories are ignored.
    
    :returns: a tuple with directory count, file count and total size.
    :rtype: (int, int, int)
    """
    dir_count = 0
    file_count = 0
    total_size = 0
    for (pathname, dirnames, filenames) in os.walk(path):
        dir_count += len(dirnames)
        file_count += len(filenames)
        fullnames = ifilterfalse(islink, imap(lambda x: join(pathname, x),
                                              chain(dirnames, filenames)))
        total_size += sum(imap(getsize, fullnames))
    return (dir_count, file_count, total_size)


def print_sizes(path):
    """Prints the sizes and names of the directories under `path` (recursivly)
    and the sizes and names of the files under `path` (non-recursive) plus a
    grand total of bytes.
    """
    grand_total = 0
    (dirnames, filenames_and_sizes) = dir_and_filenames(path)
    print '    size       type   dirs/files name'
    print ':' * 70
    # 
    # Print directories.
    # 
    for dirname in dirnames:
        fullname = join(path, dirname)
        (dir_count, file_count, total_size) = dir_statistic(fullname)
        grand_total += total_size
        print '%12s   DIR   %5d/%-5d %s' % (format_bytesize(total_size),
                                            dir_count, file_count, dirname)
    # 
    # Print files.
    # 
    for (name, size) in filenames_and_sizes:
        grand_total += size
        print '%12s   file              %s' % (format_bytesize(size), name)
    # 
    # And the grand total.
    # 
    print '------------------\n%12s total' % format_bytesize(grand_total)


if __name__ == '__main__':
    print_sizes(sys.argv[1])
Benutzeravatar
knekke
User
Beiträge: 100
Registriert: Freitag 29. Oktober 2004, 17:23
Wohnort: Schweden

In einem Wort: Deluxe!!!
Vielen Dank!!!!! :D
Antworten