Finden Sie die Größe und den freien Speicherplatz des Dateisystems, das eine bestimmte Datei enthält

76

Ich verwende Python 2.6 unter Linux. Was ist der schnellste Weg:

  • um festzustellen, welche Partition ein bestimmtes Verzeichnis oder eine bestimmte Datei enthält?

    Angenommen, das /dev/sda2ist montiert /homeund /dev/mapper/fooist montiert /home/foo. Aus der Zeichenfolge "/home/foo/bar/baz"möchte ich das Paar wiederherstellen ("/dev/mapper/foo", "home/foo").

  • und dann, um Nutzungsstatistiken der angegebenen Partition zu erhalten? Zum Beispiel /dev/mapper/foomöchte ich die Größe der Partition und den verfügbaren freien Speicherplatz (entweder in Bytes oder ungefähr in Megabytes) erhalten.

Federico A. Ramponi
quelle
Berücksichtigen Sie Symlinks? Während Sie möglicherweise / home und / mnt / somedisk haben, kann / home / foo / x ein Symlink zum Verzeichnis / mnt / somedisk / xyzzy sein - es erscheint also unter / home, lebt aber tatsächlich unter / mnt / somedisk
Piskvor hat das verlassen Gebäude
@Piskvor: Nein - vorerst muss ich keinen Symlinks folgen, es sind nur einfache Verzeichnisse. Die erste Frage lautet im Grunde: "Finde das nächstgelegene Vorfahrenverzeichnis, auf dem eine Partition gemountet ist".
Federico A. Ramponi
Siehe auch stackoverflow.com/questions/3274354/…
Mechanische Schnecke

Antworten:

49

Wenn Sie nur den freien Speicherplatz auf einem Gerät benötigen, lesen Sie die Antwort os.statvfs()unten.

Wenn Sie auch den Gerätenamen und den Einhängepunkt benötigen, die der Datei zugeordnet sind, sollten Sie ein externes Programm aufrufen, um diese Informationen abzurufen. dfliefert alle Informationen, die Sie benötigen - beim Aufruf df filenamewird eine Zeile über die Partition gedruckt, die die Datei enthält.

Um ein Beispiel zu geben:

import subprocess
df = subprocess.Popen(["df", "filename"], stdout=subprocess.PIPE)
output = df.communicate()[0]
device, size, used, available, percent, mountpoint = \
    output.split("\n")[1].split()

Beachten Sie, dass dies ziemlich spröde ist, da es vom genauen Format der dfAusgabe abhängt , aber mir ist keine robustere Lösung bekannt. (Es gibt einige Lösungen, die auf dem folgenden /procDateisystem basieren und noch weniger portabel sind als dieses.)

Sven Marnach
quelle
1
Insbesondere konnte er Befehle importieren und dann befehle.getoutput ("df filename | tail -1 | gawk '{print $ 6}'")
dr jimbob
8
Das commandsModul wird ersetzt durch subprocess. Und ich würde die Ausgabe nicht in Bash analysieren, wenn ich es in Python tun kann :)
Sven Marnach
4
Ich wusste nichts über das Argument "Dateiname" für df. "df -B MB Dateiname" reicht aus. Danke vielmals.
Federico A. Ramponi
2
Diese Methode funktioniert nicht immer. In meiner Umgebung verbraucht die Ausgabe mehr als eine Zeile. In diesem Fall wird das Skript abgerufen ValueError('need more than 5 values to unpack', da sich die Gerätespalte und andere Informationen in den verschiedenen Zeilen befinden.
Liuyix
4
@liuyix Diese Antwort ist für Linux und dfspeziell von GNU Coreutils. Wenn Sie den Gerätenamen und den Einhängepunkt nicht benötigen, verwenden Sie bitte den Code aus der nächsten Antwort.
Sven Marnach
124

Dies gibt nicht den Namen der Partition an, aber Sie können die Dateisystemstatistik direkt über den statvfsUnix-Systemaufruf abrufen. Verwenden Sie zum Aufrufen von Python os.statvfs('/home/foo/bar/baz').

Die relevanten Felder im Ergebnis laut POSIX :

unsigned long f_frsize   Fundamental file system block size. 
fsblkcnt_t    f_blocks   Total number of blocks on file system in units of f_frsize. 
fsblkcnt_t    f_bfree    Total number of free blocks. 
fsblkcnt_t    f_bavail   Number of free blocks available to 
                         non-privileged process.

Um die Werte zu verstehen, multiplizieren Sie mit f_frsize:

import os
statvfs = os.statvfs('/home/foo/bar/baz')

statvfs.f_frsize * statvfs.f_blocks     # Size of filesystem in bytes
statvfs.f_frsize * statvfs.f_bfree      # Actual number of free bytes
statvfs.f_frsize * statvfs.f_bavail     # Number of free bytes that ordinary users
                                        # are allowed to use (excl. reserved space)
Mechanische Schnecke
quelle
Ich hatte gerade diesen Fehler auf einem eingebetteten System mit Ubifs. Es ergab 100 MB frei, wo nur 10 verfügbar waren. Ich bin mir nicht sicher, woher die 100 kamen.
Halfgaar
26

Ab Python 3.3 gibt es eine einfache und direkte Möglichkeit, dies mit der Standardbibliothek zu tun:

$ cat free_space.py 
#!/usr/bin/env python3

import shutil

total, used, free = shutil.disk_usage(__file__)
print(total, used, free)

$ ./free_space.py 
1007870246912 460794834944 495854989312

Diese Zahlen sind in Bytes angegeben. Weitere Informationen finden Sie in der Dokumentation .

Xiong Chiamiov
quelle
24
import os

def get_mount_point(pathname):
    "Get the mount point of the filesystem containing pathname"
    pathname= os.path.normcase(os.path.realpath(pathname))
    parent_device= path_device= os.stat(pathname).st_dev
    while parent_device == path_device:
        mount_point= pathname
        pathname= os.path.dirname(pathname)
        if pathname == mount_point: break
        parent_device= os.stat(pathname).st_dev
    return mount_point

def get_mounted_device(pathname):
    "Get the device mounted at pathname"
    # uses "/proc/mounts"
    pathname= os.path.normcase(pathname) # might be unnecessary here
    try:
        with open("/proc/mounts", "r") as ifp:
            for line in ifp:
                fields= line.rstrip('\n').split()
                # note that line above assumes that
                # no mount points contain whitespace
                if fields[1] == pathname:
                    return fields[0]
    except EnvironmentError:
        pass
    return None # explicit

def get_fs_freespace(pathname):
    "Get the free space of the filesystem containing pathname"
    stat= os.statvfs(pathname)
    # use f_bfree for superuser, or f_bavail if filesystem
    # has reserved space for superuser
    return stat.f_bfree*stat.f_bsize

Einige Beispielpfadnamen auf meinem Computer:

path 'trash':
  mp /home /dev/sda4
  free 6413754368
path 'smov':
  mp /mnt/S /dev/sde
  free 86761562112
path '/usr/local/lib':
  mp / rootfs
  free 2184364032
path '/proc/self/cmdline':
  mp /proc proc
  free 0

PS

Wenn unter Python ≥3.3, gibt es shutil.disk_usage(path)ein benanntes Tupel, (total, used, free)das in Bytes ausgedrückt wird.

tzot
quelle
Wie oben erwähnt: Ich hatte gerade diese Methode mit statvfs auf einem eingebetteten System mit Ubifs fehlgeschlagen. Es ergab 100 MB frei, wo nur 10 verfügbar waren. Ich bin mir nicht sicher, woher die 100 kamen.
Halfgaar
14

Dies sollte alles machen, was Sie gefragt haben:

import os
from collections import namedtuple

disk_ntuple = namedtuple('partition',  'device mountpoint fstype')
usage_ntuple = namedtuple('usage',  'total used free percent')

def disk_partitions(all=False):
    """Return all mountd partitions as a nameduple.
    If all == False return phyisical partitions only.
    """
    phydevs = []
    f = open("/proc/filesystems", "r")
    for line in f:
        if not line.startswith("nodev"):
            phydevs.append(line.strip())

    retlist = []
    f = open('/etc/mtab', "r")
    for line in f:
        if not all and line.startswith('none'):
            continue
        fields = line.split()
        device = fields[0]
        mountpoint = fields[1]
        fstype = fields[2]
        if not all and fstype not in phydevs:
            continue
        if device == 'none':
            device = ''
        ntuple = disk_ntuple(device, mountpoint, fstype)
        retlist.append(ntuple)
    return retlist

def disk_usage(path):
    """Return disk usage associated with path."""
    st = os.statvfs(path)
    free = (st.f_bavail * st.f_frsize)
    total = (st.f_blocks * st.f_frsize)
    used = (st.f_blocks - st.f_bfree) * st.f_frsize
    try:
        percent = ret = (float(used) / total) * 100
    except ZeroDivisionError:
        percent = 0
    # NB: the percentage is -5% than what shown by df due to
    # reserved blocks that we are currently not considering:
    # http://goo.gl/sWGbH
    return usage_ntuple(total, used, free, round(percent, 1))


if __name__ == '__main__':
    for part in disk_partitions():
        print part
        print "    %s\n" % str(disk_usage(part.mountpoint))

Auf meiner Box wird der obige Code gedruckt:

giampaolo@ubuntu:~/dev$ python foo.py 
partition(device='/dev/sda3', mountpoint='/', fstype='ext4')
    usage(total=21378641920, used=4886749184, free=15405903872, percent=22.9)

partition(device='/dev/sda7', mountpoint='/home', fstype='ext4')
    usage(total=30227386368, used=12137168896, free=16554737664, percent=40.2)

partition(device='/dev/sdb1', mountpoint='/media/1CA0-065B', fstype='vfat')
    usage(total=7952400384, used=32768, free=7952367616, percent=0.0)

partition(device='/dev/sr0', mountpoint='/media/WB2PFRE_IT', fstype='iso9660')
    usage(total=695730176, used=695730176, free=0, percent=100.0)

partition(device='/dev/sda6', mountpoint='/media/Dati', fstype='fuseblk')
    usage(total=914217758720, used=614345637888, free=299872120832, percent=67.2)
Giampaolo Rodolà
quelle
1
Schauen Sie sich auch dieses Rezept an: code.activestate.com/recipes/577972-disk-usage
Giampaolo Rodolà
Ein kleiner Nitpick - allist eine integrierte Funktion und sollte nicht als Variable in einer Funktion verwendet werden.
Adam Matan
Kann dies in Gigabyte dargestellt werden?
Koustuv Chatterjee
9

Der einfachste Weg, es herauszufinden.

import os
from collections import namedtuple

DiskUsage = namedtuple('DiskUsage', 'total used free')

def disk_usage(path):
    """Return disk usage statistics about the given path.

    Will return the namedtuple with attributes: 'total', 'used' and 'free',
    which are the amount of total, used and free space, in bytes.
    """
    st = os.statvfs(path)
    free = st.f_bavail * st.f_frsize
    total = st.f_blocks * st.f_frsize
    used = (st.f_blocks - st.f_bfree) * st.f_frsize
    return DiskUsage(total, used, free)
Moskito
quelle
gebraucht = total - frei?
AK47
6

Für den ersten Punkt können Sie versuchen os.path.realpath, einen kanonischen Pfad zu erhalten. Vergleichen Sie ihn mit /etc/mtab(ich würde eigentlich vorschlagen, anzurufen getmntent, aber ich kann keinen normalen Weg finden, um darauf zuzugreifen), um die längste Übereinstimmung zu finden. (Um sicherzugehen, sollten Sie wahrscheinlich statsowohl die Datei als auch den vermuteten Mountpoint verwenden, um zu überprüfen, ob sie sich tatsächlich auf demselben Gerät befinden.)

Verwenden Sie für den zweiten Punkt os.statvfsInformationen zum Abrufen der Blockgröße und der Verwendung.

(Haftungsausschluss: Ich habe nichts davon getestet, das meiste, was ich weiß, stammt aus den Coreutils-Quellen.)

Hasturkun
quelle
re getmntent: Nun, es gibt immer die Möglichkeit import ctypes; ctypes.cdll.LoadLibrary("libc.so.6").getmntent, aber es ist nicht so einfach ...
tzot
Ich bin gespannt, warum dies eine Abwertung bekommen hat, ein Kommentar wäre
wünschenswert
6

Für den zweiten Teil Ihrer Frage, "Nutzungsstatistiken der angegebenen Partition abrufen ", macht psutil dies mit der Funktion disk_usage (path) einfach . Gibt bei einem angegebenen Pfad disk_usage()ein benanntes Tupel zurück, das den gesamten, verwendeten und freien Speicherplatz in Byte sowie den prozentualen Verbrauch enthält.

Einfaches Beispiel aus der Dokumentation:

>>> import psutil
>>> psutil.disk_usage('/')
sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)

Psutil funktioniert unter anderem mit Python-Versionen von 2.6 bis 3.6 sowie unter Linux, Windows und OSX.

Andrew
quelle
4
import os

def disk_stat(path):
    disk = os.statvfs(path)
    percent = (disk.f_blocks - disk.f_bfree) * 100 / (disk.f_blocks -disk.f_bfree + disk.f_bavail) + 1
    return percent


print disk_stat('/')
print disk_stat('/data')
LawrenceLi
quelle
1
Während dieser Code die Frage möglicherweise beantwortet, würde die Bereitstellung eines zusätzlichen Kontexts darüber, wie und / oder warum das Problem gelöst wird, den langfristigen Wert der Antwort verbessern.
Donald Duck
disk_statMethode akzeptiert keine Argumente. Aber die Idee zu verwenden os.statvfsist gut.
Suripoori
1

Normalerweise /procenthält das Verzeichnis solche Informationen unter Linux, es ist ein virtuelles Dateisystem. Gibt beispielsweise /proc/mountsInformationen zu aktuell bereitgestellten Datenträgern an. und Sie können es direkt analysieren. Dienstprogramme wie top, dfalle nutzen /proc.

Ich habe es nicht verwendet, aber dies könnte auch helfen, wenn Sie einen Wrapper möchten: http://bitbucket.org/chrismiles/psi/wiki/Home

ustun
quelle
0

Das Überprüfen der Festplattennutzung auf Ihrem Windows-PC kann wie folgt erfolgen:

import psutil

fan = psutil.disk_usage(path="C:/")
print("Available: ", fan.total/1000000000)
print("Used: ", fan.used/1000000000)
print("Free: ", fan.free/1000000000)
print("Percentage Used: ", fan.percent, "%")
Crispen Gari
quelle