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


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.