Tìm kích thước và dung lượng trống của hệ thống tệp chứa một tệp nhất định


76

Tôi đang sử dụng Python 2.6 trên Linux. Cách nhanh nhất là gì:

  • để xác định phân vùng nào chứa một thư mục hoặc tệp nhất định?

    Ví dụ: giả sử /dev/sda2được gắn trên /home/dev/mapper/foođược gắn trên /home/foo. Từ chuỗi, "/home/foo/bar/baz"tôi muốn khôi phục cặp ("/dev/mapper/foo", "home/foo").

  • và sau đó, để có được số liệu thống kê sử dụng của phân vùng đã cho? Ví dụ, /dev/mapper/footôi muốn lấy kích thước của phân vùng và dung lượng trống có sẵn (tính bằng byte hoặc xấp xỉ megabyte).


Bạn có đang tính đến các liên kết tượng trưng không? Mặc dù bạn có thể có / home và / mnt / somedisk, / home / foo / x có thể là một liên kết tượng trưng đến thư mục / mnt / somedisk / xyzzy - vì vậy nó xuất hiện dưới / home, nhưng thực sự tồn tại tại / mnt / somedisk
Piskvor để lại xây dựng

@Piskvor: Không - tạm thời tôi không cần theo dõi các liên kết tượng trưng, ​​chúng chỉ là những thư mục đơn giản. Câu hỏi đầu tiên về cơ bản là hỏi "tìm thư mục tổ tiên gần nhất có phân vùng được gắn trên đó".
Federico A. Ramponi

Câu trả lời:


49

Nếu bạn chỉ cần dung lượng trống trên một thiết bị, hãy xem câu trả lời bằng cách sử dụng os.statvfs()bên dưới.

Nếu bạn cũng cần tên thiết bị và điểm gắn kết được liên kết với tệp, bạn nên gọi một chương trình bên ngoài để lấy thông tin này. dfsẽ cung cấp tất cả thông tin bạn cần - khi được gọi khi df filenamenó in ra một dòng về phân vùng chứa tệp.

Để đưa ra một ví dụ:

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

Lưu ý rằng điều này khá giòn, vì nó phụ thuộc vào định dạng chính xác của dfđầu ra, nhưng tôi không biết giải pháp nào mạnh mẽ hơn. (Có một số giải pháp dựa trên /prochệ thống tệp bên dưới thậm chí còn kém di động hơn hệ thống này).


1
Cụ thể, anh ấy có thể thực hiện các lệnh nhập, sau đó là các lệnh.getoutput ("df filename | tail -1 | gawk '{print $ 6}'")
dr jimbob

8
Các commandsmô-đun được thay thế bởi subprocess. Và tôi sẽ không làm sản lượng phân tích cú pháp trong bash khi tôi có thể làm điều đó bằng Python :)
Sven Marnach

4
Tôi không biết về đối số "tên tệp" đối với df. "Tên tệp df -B MB" sẽ làm được. Cảm ơn rất nhiều.
Federico A. Ramponi

2
phương pháp này không phải lúc nào cũng hoạt động. Trong môi trường của tôi, đầu ra tiêu thụ nhiều hơn một dòng. Trong trường hợp đó, tập lệnh nhận được ValueError('need more than 5 values to unpack', vì cột thiết bị và các thông tin khác nằm ở các dòng khác nhau.
liuyix

4
@liuyix Câu trả lời này dành riêng cho Linux và dftừ các coreutils GNU. Nếu bạn không cần tên thiết bị và điểm gắn kết, vui lòng sử dụng mã từ câu trả lời tiếp theo.
Sven Marnach

124

Điều này không cung cấp tên của phân vùng, nhưng bạn có thể lấy thống kê hệ thống tệp trực tiếp bằng statvfslệnh gọi hệ thống Unix. Để gọi nó từ Python, hãy sử dụng os.statvfs('/home/foo/bar/baz').

Các trường liên quan trong kết quả, theo 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.

Vì vậy, để hiểu các giá trị, hãy nhân với 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)

Tôi vừa gặp lỗi này trên một hệ thống nhúng có ubifs. Nó dẫn đến 100MB miễn phí trong khi chỉ có 10. Tôi không chắc số 100 đến từ đâu.
Halfgaar

27

Kể từ Python 3.3, có một cách dễ dàng và trực tiếp để thực hiện việc này với thư viện chuẩn:

$ 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

Những con số này tính bằng byte. Xem tài liệu để biết thêm thông tin.


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

Một số tên đường dẫn mẫu trên máy tính của tôi:

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

nếu trên Python ≥3.3, sẽ shutil.disk_usage(path)trả về một bộ giá trị được đặt tên được (total, used, free)biểu thị bằng byte.


Như đã lưu ý ở trên: Tôi vừa gặp phải phương pháp này bằng cách sử dụng statvfs bị lỗi trên hệ thống nhúng có ubifs. Nó dẫn đến 100MB miễn phí trong khi chỉ có 10. Tôi không chắc số 100 đến từ đâu.
Halfgaar

14

Điều này sẽ làm cho mọi thứ bạn yêu cầu:

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

Trên hộp của tôi, mã trên in:

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
Ngoài ra, hãy xem công thức này: code.activestate.com/recipes/577972-disk-usage
Giampaolo Rodolà

Một nitpick nhỏ - alllà một hàm được tích hợp sẵn và không nên được sử dụng như một biến trong một hàm.
Adam Matan

Điều này có thể được biểu diễn bằng Gigabyte không?
Koustuv Chatterjee

9

Cách đơn giản nhất để tìm ra nó.

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)

đã sử dụng = tổng số - miễn phí?
AK47,

6

Đối với điểm đầu tiên, bạn có thể thử sử dụng os.path.realpathđể lấy một đường dẫn chuẩn, kiểm tra nó /etc/mtab(tôi thực sự khuyên bạn nên gọi getmntent, nhưng tôi không thể tìm thấy cách thông thường để truy cập nó) để tìm kết quả phù hợp dài nhất. (để chắc chắn, bạn có thể nên statcả tệp và điểm gắn kết giả định để xác minh rằng chúng trên thực tế trên cùng một thiết bị)

Đối với điểm thứ hai, sử dụng os.statvfsđể lấy kích thước khối và thông tin sử dụng.

(Tuyên bố từ chối trách nhiệm: Tôi chưa thử nghiệm điều này, hầu hết những gì tôi biết đều đến từ các nguồn coreutils)


tái getmntent: tốt, luôn có khả năng xảy ra import ctypes; ctypes.cdll.LoadLibrary("libc.so.6").getmntent, nhưng nó không phải là đơn giản ...
tzot

Tôi tò mò là tại sao này có một downvote, một lời nhận xét sẽ được đánh giá cao
Hasturkun

6

Đối với phần thứ hai của câu hỏi của bạn, "lấy thống kê sử dụng của phân vùng đã cho", psutil làm điều này dễ dàng với hàm disk_usage (path) . Đưa ra một đường dẫn, disk_usage()trả về một bộ giá trị được đặt tên bao gồm tổng dung lượng, đã sử dụng và dung lượng trống được biểu thị bằng byte, cộng với phần trăm sử dụng.

Ví dụ đơn giản từ tài liệu:

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

Psutil hoạt động với các phiên bản Python từ 2.6 đến 3.6 và trên Linux, Windows và OSX cùng các nền tảng khác.


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
Mặc dù mã này có thể trả lời câu hỏi, nhưng việc cung cấp ngữ cảnh bổ sung về cách thức và / hoặc lý do tại sao nó giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời.
Donald Duck

disk_statphương thức không nhận bất kỳ đối số nào. Nhưng, ý tưởng để sử dụng os.statvfslà tốt.
suripoori

1

Thông thường /procthư mục chứa thông tin như vậy trong Linux, nó là một hệ thống tệp ảo. Ví dụ, /proc/mountscung cấp thông tin về các đĩa được gắn kết hiện tại; và bạn có thể phân tích cú pháp trực tiếp. Các tiện ích như top,df tất cả đều tận dụng/proc .

Tôi chưa sử dụng nó, nhưng điều này cũng có thể hữu ích, nếu bạn muốn có một trình bao bọc: http://bitbucket.org/chrismiles/psi/wiki/Home


0

Kiểm tra mức sử dụng đĩa trên PC Windows của bạn có thể được thực hiện như sau:

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, "%")
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.