获取文件的实际磁盘空间

18

如何在Python中获取文件在磁盘上的实际大小?(它在硬盘上占用的实际空间大小)。


你的意思是按簇大小向上取整吗? - ruslik
2
看一下这个问题:https://dev59.com/9HE95IYBdhLWcg3wCJNf - Ruel
@ruslik:这并不简单。考虑稀疏或压缩文件,它们可以占用比其大小指示的空间更少的空间。 - Philipp
7个回答

18

仅限UNIX操作系统:

import os
from collections import namedtuple

_ntuple_diskusage = namedtuple('usage', 'total used free')

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

    Returned valus is a named tuple 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 _ntuple_diskusage(total, used, free)

使用方法:

>>> disk_usage('/')
usage(total=21378641920, used=7650934784, free=12641718272)
>>>

编辑1 - 适用于Windows:https://code.activestate.com/recipes/577972-disk-usage/?in=user-4178764

编辑2 - 在Python 3.3+中也可以使用:https://docs.python.org/3/library/shutil.html#shutil.disk_usage


7
以下是获取文件磁盘大小的正确方法,适用于 st_blocks 已设置的平台:
import os

def size_on_disk(path):
    st = os.stat(path)
    return st.st_blocks * 512

其他答案指出应该乘以os.stat(path).st_blksizeos.vfsstat(path).f_bsize是错误的。

Python文档中对os.stat_result.st_blocks的描述非常清楚:

st_blocks
文件分配的512字节块数。当文件有空洞时,这可能比st_size/512小。

此外,stat(2) man页面也说明了同样的事情:

blkcnt_t  st_blocks;      /* Number of 512B blocks allocated */

5
更新于2021年3月26日:之前,我的回答将文件的逻辑大小四舍五入为块大小的整数倍。这种方法仅在文件存储在磁盘上连续的块序列中(或者所有块都已满,只剩下一个块未满)时才有效。由于这是一个特殊情况(虽然对于小文件很常见),因此我已经更新了我的答案以使其更加普遍正确。但是,请注意不幸的是,在一些系统(例如Windows 10)上可能无法使用statvfs方法和st_blocks值。
调用os.stat(filename).st_blocks以获取文件中块的数量。
调用os.statvfs(filename).f_bsize以获取文件系统块大小。
然后按以下方式计算正确的磁盘大小:
num_blocks = os.stat(filename).st_blocks
block_size = os.statvfs(filename).f_bsize
sizeOnDisk = num_blocks*block_size

4
“((lSize-1)/bSize+1)*bSize)” 可能会更加准确。感谢您纠正我古老而错误的答案。 - ephemient
自2.6版本起已弃用:statvfs模块在Python 3中已被移除。 :-( https://docs.python.org/2/library/statvfs.html - danodonovan
@danodonovan 看起来在Python 3中已经删除了statvfs模块,但是答案使用了os模块。正如您所看到的,Python 3的文档显示os.statvfs仍然存在,并且甚至在Python 3.6中更新以包括新功能。 - bytesized
我在处理较大文件时遇到了一个问题,使用你提供的两个公式得出的值比du给出的值小1个块(4,096字节)。例如,如果您使用命令dd if=/dev/zero of=testsize bs=1 count=419472426创建一个文件。换句话说,使用du的--apparent-size选项得出的结果与实际值相差7,126而不是4,096。请注意:使用du的--apparent-size选项得出的值与os.stat(filename).st_size获得的值相匹配。 - user1748155
根据 POSIX - https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html - "st_blocks" 和 "st_blksize" 的值与 "f_bsize"(来自 <sys/statvfs.h>) 结构成员的值没有关联。因此,除非 Python 提供了比 POSIX 更强的保证,否则假设 statvfs 返回的 f_bsize 是 st_blocks 的正确单位可能不总是准确的。 - Simon Kissane

2

实际上已经过去了12年,但至今没有关于如何在Windows上完成此操作的答案...

以下是通过ctypes在Windows上查找“磁盘空间大小”的方法:

import ctypes
def GetSizeOnDisk(path):
    '''https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getcompressedfilesizew'''
    filesizehigh = ctypes.c_ulonglong(0) # not sure about this... something about files >4gb
    return ctypes.windll.kernel32.GetCompressedFileSizeW(ctypes.c_wchar_p(path),ctypes.pointer(filesizehigh))

'''
>>> os.stat(somecompressedorofflinefile).st_size
943141
>>> GetSizeOnDisk(somecompressedorofflinefile)
671744
>>>
'''

谢谢!我一直在寻找这个。奇怪的是,当OneDrive将文件状态显示为“仅在线时可用”时,您的函数几乎总是返回零大小,这正是我想要的。但出于某种奇怪的原因,有时它会显示完整的大小,即使文件仅在在线时可用。不知道为什么。 - Michael

2
st = os.stat(…)
du = st.st_blocks * st.st_blksize

+1,没想到这个可以在os.stat中找到!我本来要把提问者引用到win32file.DeviceIoControl。不知道为什么我假设OP是在Windows上:P - fmark
在某些Unix系统(如Linux)中,也可能有以下属性:st_blocks(文件分配的块数),st_blksize(文件系统块大小)......也就是说,这些不是可移植的属性,当这些成员不可用时,您至少应该捕获引发的异常。 - Philipp
12
小心,这是错误的!在Linux系统中,st.st_blocks始终以512字节为单位,而st.st_blksize是文件系统块大小(通常为4096字节)。真正的用法是 st.st_blocks * 512。请参阅 http://linux.die.net/man/2/stat 了解更多详细信息。 - Jim Paris
1
不,你们两个都错了:st.st_blocks并不总是以512字节为单位。在我的机器上,它是以1024的倍数为单位的(这确实很奇怪)。此外,答案是错误的,因为st_blksize并不返回1024,它返回文件I/O块大小,例如,在我的戴尔笔记本电脑上运行python 2.7.8的cygwin上的Windows 7上,我创建了一个3000字节的文件("dd if=/dev/zero bs=3000 count=1 of=./testfile.txt"),然后:os.stat("testfile.txt").st_blocks=4; os.stat("./testfile.txt").st_blksize=65536; 逻辑大小为3000,在磁盘上为4096。我将在下面回答。 - hft
你能否更新你的回答,引用下面 @hft 的回答? - Miserable Variable

0

我不确定这是磁盘上的大小还是逻辑大小:

import os
filename = "/home/tzhx/stuff.wev"
size = os.path.getsize(filename)

如果这不是你要找的机器人,你可以通过将其除以集群大小(作为浮点数),然后使用 ceil 函数向上取整,最后再乘回来。


当我在Windows7,Python 2.2中使用getsize()时,我确实得到了文件占用的实际空间。在我的情况下,我只需要“文件大小”而不是“文件空间”。我想知道如何仅获取文件大小。 - Allan Ruin

0
要获取给定文件/文件夹的磁盘使用情况,您可以执行以下操作:
import os

def disk_usage(path):
    """Return cumulative number of bytes for a given path."""
    # get total usage of current path
    total = os.path.getsize(path)
    # if path is dir, collect children
    if os.path.isdir(path):
        for file_name in os.listdir(path):
            child = os.path.join(path, file_name)
            # recursively get byte use for children
            total += disk_usage(child)
    return total

该函数递归地收集给定路径内嵌文件的字节使用情况,并返回整个路径的累计使用情况。如果您想打印每个文件的信息,也可以在其中添加print "{path}: {bytes}".format(path, total)

在运行多个测试后,在Windows 7上,它返回实际大小,而不是磁盘上的大小。 - Steve Byrne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接