Знайдіть розмір і вільний простір файлової системи, що містить даний файл


76

Я використовую Python 2.6 на Linux. Який найшвидший спосіб:

  • щоб визначити, який розділ містить даний каталог або файл?

    Наприклад, припустимо, що /dev/sda2встановлено на /homeта /dev/mapper/fooвстановлено /home/foo. Із рядка "/home/foo/bar/baz"я хотів би відновити пару ("/dev/mapper/foo", "home/foo").

  • а потім отримати статистику використання даного розділу? Наприклад, з огляду на те, що /dev/mapper/fooя хотів би отримати розмір розділу та вільний простір (або в байтах, або приблизно в мегабайтах).


Ви берете до уваги символічні посилання? Хоча у вас може бути / home та / mnt / somedisk, / home / foo / x може бути символічним посиланням на каталог / mnt / somedisk / xyzzy - так воно відображається під / home, але насправді живе в / mnt / somedisk
— Piskvor залишив будівля

@Piskvor: Ні - поки що мені не потрібно переходити за символічними посиланнями, це просто каталоги. Перше питання в основному полягає в тому, щоб "знайти найближчий каталог предків, на якому встановлений розділ".
— Федеріко А. Рампоні,

Відповіді:


49

Якщо вам просто потрібен вільний простір на пристрої, див. Відповідь, використовуючи os.statvfs()нижче.

Якщо вам також потрібно ім’я пристрою та точка монтування, пов’язані з файлом, вам слід зателефонувати зовнішній програмі, щоб отримати цю інформацію. dfнадасть всю необхідну інформацію - при виклику під df filenameчас друку рядка про розділ, що містить файл.

Для прикладу:

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()

Зауважте, що це досить крихко, оскільки це залежить від точного формату dfвиводу, але я не знаю більш надійного рішення. (Нижче наведено декілька рішень, які покладаються на /procфайлову систему, яка є навіть менш портативною, ніж ця.)


1
Зокрема, він міг виконувати команди імпорту, потім commands.getoutput ("df ім'я файлу | tail -1 | gawk '{print $ 6}'")
— dr jimbob

8
commandsМодуль замінюється subprocess. І я б не виконував синтаксичний аналіз виводу в bash, коли я можу це зробити на Python :)
— Свен Марнах

4
Я не знав про аргумент "ім'я файлу" для df. "df -B MB ім'я файлу" підійде. Дуже дякую.
— Федеріко А. Рампоні,

2
цей метод працює не завжди. У моєму середовищі вихід споживає більше одного рядка. У цьому випадку скрипт отримує ValueError('need more than 5 values to unpack', оскільки стовпець пристрою та інші відомості знаходяться в різних рядках.
— liuyix

4
@liuyix Ця відповідь стосується Linux та, зокрема, dfGNU coreutils. Якщо вам не потрібні назва пристрою та точка монтування, скористайтеся кодом із наступної відповіді.
— Свен Манах

124

Це не дає назви розділу, але ви можете отримати статистику файлової системи безпосередньо за допомогою statvfsсистемного виклику Unix. Щоб викликати його з Python, використовуйте os.statvfs('/home/foo/bar/baz').

Відповідні поля в результаті, згідно 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.

Отже, щоб зрозуміти значення, помножте на 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)

У мене просто сталася ця помилка у вбудованій системі з ubifs. В результаті ви отримали 100 МБ безкоштовно, де було доступно лише 10. Я не впевнений, звідки взявся 100.
— Halfgaar

27

Що стосується Python 3.3, існує простий і прямий спосіб зробити це за допомогою стандартної бібліотеки:

$ 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

Ці числа в байтах. Для отримання додаткової інформації дивіться документацію .


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

Деякі зразки імен шляхів на моєму комп’ютері:

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

якщо на Python ≥3,3, там shutil.disk_usage(path)повертається іменований кортеж, (total, used, free)виражений у байтах.


Як зазначалося вище: у мене щойно цей метод із використанням statvfs зазнав невдачі у вбудованій системі з ubifs. В результаті ви отримали 100 МБ безкоштовно, де було доступно лише 10. Я не впевнений, звідки взявся 100.
— Halfgaar

14

Це має зробити все, що ви запитали:

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))

У моєму вікні код вище друкує:

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)

1
Також погляньте на цей рецепт: code.activestate.com/recipes/577972-disk-usage
— Джампаоло Родола

Незначний затримка - allце вбудована функція і не повинна використовуватися як змінна у функції.
— Адам Матан

Чи можна це представити в гігабайтах?
— Koustuv Chatterjee

9

Найпростіший спосіб це дізнатись.

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)

використовується = всього - безкоштовно?
— AK47

6

Для першого пункту ви можете спробувати використовувати os.path.realpath щоб отримати канонічний шлях, перевірити його /etc/mtab(я б насправді запропонував зателефонувати getmntent, але я не можу знайти звичайний спосіб отримати до нього доступ), щоб знайти найдовший збіг. (безумовно, вам слід, мабуть, statі файл, і передбачувану точку монтування перевірити, що вони насправді знаходяться на одному пристрої)

Для другого пункту використовуйте, os.statvfsщоб отримати інформацію про розмір блоку та використання.

(Застереження: я нічого з цього не перевірив, більшість із того, що я знаю, походить із джерел coreutils)


re getmntent: ну, завжди є можливість import ctypes; ctypes.cdll.LoadLibrary("libc.so.6").getmntent, але це не так просто ...
— tzot

Мені цікаво, чому це отримало голос проти, коментар був би вдячний
— Гастуркун

6

Що стосується другої частини Вашого запитання, "отримати статистику використання даного розділу", psutil полегшує це за допомогою функції disk_usage (path) . Даний шлях, disk_usage()повертає названий кортеж, що включає загальний, використаний та вільний простір, виражений у байтах, плюс відсоток використання.

Простий приклад з документації:

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

Psutil працює з версіями Python з 2.6 до 3.6 та на Linux, Windows та OSX серед інших платформ.


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')

1
Хоча цей код може відповісти на питання, надання додаткового контексту щодо того, як та / або чому він вирішує проблему, покращило б довгострокове значення відповіді.
— Дональд Дак

disk_statметод не бере жодних аргументів. Але ідея використовувати os.statvfsхороша.
— suripoori

1

Зазвичай /procкаталог містить таку інформацію в Linux, це віртуальна файлова система. Наприклад, /proc/mountsдає інформацію про поточно встановлені диски; і ви можете проаналізувати його безпосередньо. Комунальні послуги, як top, dfусі використовують/proc .

Я не використовував його, але це також може допомогти, якщо ви хочете обгортку: http://bitbucket.org/chrismiles/psi/wiki/Home


0

Перевірку використання диска на ПК з ОС Windows можна виконати наступним чином:

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, "%")
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.