使用 Python 获取文件在磁盘上的实际占用空间


使用 python 获取文件在磁盘上的实际占用空间

本文深入探讨了如何使用 Python 精确计算文件在磁盘上的实际占用空间,而非其逻辑大小。文章解释了文件系统块分配原理,并提供了基于 `os.lstat` 和 `os.statvfs` 的 Python 实现,包括性能优化方案。同时,明确了该方法的适用范围(常规文件、非Windows系统)及重要注意事项,旨在帮助开发者在创建磁盘镜像或进行存储管理时避免空间不足问题。

引言:理解文件在磁盘上的真实占用

在文件系统管理中,我们经常会遇到“文件大小(Size)”和“文件在磁盘上的占用空间(Size on disk)”这两个概念。它们之间存在显著差异。文件大小通常指的是文件内容的逻辑字节数,而文件在磁盘上的占用空间则是文件系统为存储该文件实际分配的物理块数量的总和。由于文件系统以固定大小的块(例如,4KB)来分配存储空间,即使一个文件只有1字节,它也可能占用一个完整的磁盘块。

在需要精确控制存储空间分配的场景中,例如使用 dd 命令创建磁盘镜像文件(img 容器)时,准确获取文件或目录的实际磁盘占用至关重要。如果仅依据逻辑文件大小进行空间预留,可能会因实际占用超出预期而导致“空间不足”的错误。本教程将详细介绍如何使用 Python 编程语言,通过访问文件系统底层信息来计算文件的实际磁盘占用。

Python 实现:获取文件在磁盘上的实际占用

要计算文件在磁盘上的实际占用,我们需要两个关键信息:文件的逻辑大小和文件系统块大小。Python 的 os 模块提供了访问这些信息的接口:

  • os.lstat(path):获取文件的状态信息,其中包括文件的逻辑大小(st_size)。
  • os.statvfs(path):获取文件所在文件系统的状态信息,其中包括文件系统块大小(f_frsize,通常是文件系统碎片大小或基本块大小)。

计算原理是:将文件的逻辑大小除以文件系统块大小,得到所需块的数量。如果存在余数(即文件大小不是块大小的整数倍),则需要额外分配一个块。

计算公式: 实际磁盘占用 = (文件逻辑大小 / 文件系统块大小) 的向上取整 * 文件系统块大小

在 Python 中,可以通过 divmod 函数和布尔转换来实现向上取整:

Beautiful.ai Beautiful.ai

AI在线创建幻灯片

Beautiful.ai 108 查看详情 Beautiful.ai
import os
import stat

def size_on_disk(path: str) -> int:
    """
    获取常规文件在磁盘上的实际占用空间。

    参数:
        path (str): 文件的路径。

    返回:
        int: 文件在磁盘上的实际占用字节数。

    抛出:
        NotImplementedError: 如果路径指向的不是常规文件。
    """
    st = os.lstat(path)
    # 检查是否为常规文件
    if not stat.S_ISREG(st.st_mode):
        raise NotImplementedError(f"'{path}' 不是常规文件,此函数仅支持常规文件。")

    # 获取文件系统信息
    st_vfs = os.statvfs(path)

    # 计算所需块数和剩余字节
    n_blocks, rem_bytes = divmod(st.st_size, st_vfs.f_frsize)

    # 如果有剩余字节,则需要额外一个块
    total_blocks = n_blocks + bool(rem_bytes)

    return total_blocks * st_vfs.f_frsize

# 示例用法:
if __name__ == "__main__":
    # 创建一个测试文件
    with open("test_file.txt", "w") as f:
        f.write("Hello, world!") # 13字节

    try:
        disk_size = size_on_disk("test_file.txt")
        print(f"文件 'test_file.txt' 的逻辑大小: {os.path.getsize('test_file.txt')} 字节")
        print(f"文件 'test_file.txt' 在磁盘上的实际占用: {disk_size} 字节")

        # 创建一个空文件
        open("empty_file.txt", "w").close()
        disk_size_empty = size_on_disk("empty_file.txt")
        print(f"文件 'empty_file.txt' 的逻辑大小: {os.path.getsize('empty_file.txt')} 字节")
        print(f"文件 'empty_file.txt' 在磁盘上的实际占用: {disk_size_empty} 字节")

    except NotImplementedError as e:
        print(f"错误: {e}")
    except FileNotFoundError:
        print("错误: 文件未找到,请确保测试文件存在。")
    finally:
        # 清理测试文件
        if os.path.exists("test_file.txt"):
            os.remove("test_file.txt")
        if os.path.exists("empty_file.txt"):
            os.remove("empty_file.txt")

适用范围与限制

上述 size_on_disk 函数具有以下适用范围和限制:

  • 仅限常规文件: 该函数设计用于计算常规文件(regular files)的磁盘占用。它不适用于目录、符号链接、设备文件等特殊文件类型。对于目录,其自身的元数据占用通常是少量块,而其内容占用则需要递归计算其下所有文件的磁盘占用总和。
  • 仅计算数据块占用: 此方法主要计算文件内容所占用的数据块。它不包括文件名、文件权限、时间戳等元数据在目录项或 inode 表中占用的空间。
  • 操作系统限制: 此方案适用于 Linux、Unix 或 macOS 等类 Unix 操作系统。由于 Windows 文件系统(如 NTFS)的内部机制和 API 不同,该方法不适用于 Windows 系统。

性能优化:缓存文件系统信息

在处理大量位于同一卷(磁盘分区)上的文件时,重复调用 os.statvfs(path) 会带来不必要的性能开销。因为同一个文件系统上的所有文件共享相同的块大小(f_frsize),我们可以缓存 os.statvfs 的结果,避免对同一卷进行多次系统调用。

os.lstat(path) 返回的 st_dev 字段表示文件所在的设备ID。我们可以利用这个ID作为缓存键。

import os
import stat

# 用于缓存文件系统信息的字典,键为设备ID (st_dev)
STATVFS_CACHE = {}

def size_on_disk_optimized(path: str) -> int:
    """
    获取常规文件在磁盘上的实际占用空间,并优化了文件系统信息查询。

    参数:
        path (str): 文件的路径。

    返回:
        int: 文件在磁盘上的实际占用字节数。

    抛出:
        NotImplementedError: 如果路径指向的不是常规文件。
    """
    st = os.lstat(path)
    if not stat.S_ISREG(st.st_mode):
        raise NotImplementedError(f"'{path}' 不是常规文件,此函数仅支持常规文件。")

    # 尝试从缓存获取文件系统信息
    # 如果缓存中不存在,则调用 os.statvfs 并存入缓存
    if not (st_vfs := STATVFS_CACHE.get(st.st_dev)):
        STATVFS_CACHE[st.st_dev] = (st_vfs := os.statvfs(path))

    n_blocks, rem_bytes = divmod(st.st_size, st_vfs.f_frsize)
    total_blocks = n_blocks + bool(rem_bytes)

    return total_blocks * st_vfs.f_frsize

# 示例用法(与上面类似,此处省略具体调用,仅展示函数定义)
if __name__ == "__main__":
    # 创建一个测试文件
    with open("test_file_optimized.txt", "w") as f:
        f.write("Optimized example content.") # 26字节

    try:
        disk_size = size_on_disk_optimized("test_file_optimized.txt")
        print(f"优化后:文件 'test_file_optimized.txt' 的逻辑大小: {os.path.getsize('test_file_optimized.txt')} 字节")
        print(f"优化后:文件 'test_file_optimized.txt' 在磁盘上的实际占用: {disk_size} 字节")
    except NotImplementedError as e:
        print(f"错误: {e}")
    except FileNotFoundError:
        print("错误: 文件未找到,请确保测试文件存在。")
    finally:
        if os.path.exists("test_file_optimized.txt"):
            os.remove("test_file_optimized.txt")

重要注意事项

  1. 空文件(0字节)的磁盘占用: 值得注意的是,即使是逻辑大小为0字节的空文件,在某些文件系统上仍然可能占用一个完整的块(st_vfs.f_frsize)。这是因为文件系统可能需要为文件的元数据(如 inode)分配空间。本教程提供的函数在 st.st_size 为 0 时,n_blocks 和 rem_bytes 都为 0,最终会返回 0。如果需要考虑空文件占用一个块的情况,需要额外逻辑处理,但这并非所有文件系统的普遍行为。
  2. 目录的磁盘占用: 本文提供的函数专注于常规文件的磁盘占用。要获取一个目录及其内容的整体磁盘占用,您需要:
    • 遍历目录下的所有常规文件,并使用 size_on_disk 函数累加它们的磁盘占用。
    • (可选)考虑目录本身的元数据所占用的块。这通常通过 os.lstat(directory_path).st_blocks * 512(如果 st_blocks 单位是 512 字节块)或类似方式获取,但具体实现会因文件系统而异,并且通常目录本身的占用相对较小。
  3. 跨平台兼容性: 再次强调,os.statvfs 及其相关概念主要存在于类 Unix 系统中。在 Windows 环境下,您需要使用不同的方法(如 ctypes 调用 Windows API)来获取类似的信息,这超出了本教程的范围。

总结

精确计算文件在磁盘上的实际占用空间是进行有效存储管理和避免潜在错误的关键。通过利用 Python 的 os.lstat 和 os.statvfs 函数,我们可以根据文件系统块分配的原理,准确地计算出常规文件的物理磁盘占用。同时,通过缓存文件系统信息,可以显著提升处理大量文件时的性能。理解这些底层机制及其限制,有助于开发者编写更健壮、更高效的文件系统操作代码。

以上就是使用 Python 获取文件在磁盘上的实际占用空间的详细内容,更多请关注其它相关文章!


# python  # 知识付费网站怎么推广呢  # 国内seo软件哪个好  # 营销微信群推广方案  # 大同百度seo  # sem竞价排名关键词来源的优点  # 厚街网站建设费用  # 国际营销市场推广方案  # 网站推广英语  # 泰州知名seo推广公司  # 它不  # 您需要  # 所需  # 适用于  # 则需  # 创建一个  # 递归  # 文件系统  # win  # macos  # unix  # ai  # mac  # 编程语言  # 字节  # 操作系统  # windows  # node  # linux  # 机械网站建设工程 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894 】


相关推荐: win11自带录屏文件保存在哪里 Win11 Game Bar录制视频默认路径【分享】  智慧团建活动报名入口 智慧团建活动报名入口手机端官网​  NumPy 高性能技巧:基于多列条件查找最近邻行索引的向量化实现  抖音视频如何添加标题?添加标题有哪些好处?  以下哪一个是适应长期护理制度发展而设立的新职业  《花瓣》创建专辑方法  Yandex无需登录畅游 俄罗斯搜索引擎最新官网指南  构建可配置的J*aScript加权点击计数器与共享总计功能  知乎APP怎么查看自己被邀请的问题_知乎APP邀请回答记录查看与参与方法  顺丰快递怎么查物流_顺丰快递物流信息实时查询操作指南  Python中对象引用与链表属性赋值的机制解析  解决 Vue 3 组件未定义错误:理解 createApp 与根组件的正确使用  苹果官网国补入口在哪  AO3中文版手机快速通道_AO3最新稳定链接更新  C++怎么实现一个红黑树_C++高级数据结构与平衡二叉搜索树  c++如何实现一个简单的RPC框架_c++远程过程调用原理与实践  抖音网页版官方链接 抖音网页版官网链接入口  mysql归档数据怎么导出为csv_mysql归档数据导出为csv文件的方法  在Dash应用中自定义HTML标题和网站图标  苹果iPhone14ProMax如何新建AppleID_iPhone14ProMax新建AppleID具体流程  Lar*el Eloquent:高效删除多对多关系中无关联子记录的父模型  微信客户端如何找回密码_微信客户端忘记密码找回方法  mysql镜像配置如何设置用户权限组_mysql镜像配置用户组与权限分级管理方法  《优志愿》修改手机号方法  大熊猫抓取竹子的“大拇指”其实是什么?蚂蚁庄园课堂今天答案最新11月30日  《sketchbook》选中部分图案移动方法  掌握CSS :has() 选择器:父选择器、嵌套限制与常见陷阱解析  小米手机截图后如何查看历史_小米手机截图历史记录查看方法  如何在Podman容器中运行Composer_Docker替代品Podman的PHP与Composer容器化实践  MacBook Pro词典使用指南  163邮箱网页版官方登录入口 163邮箱网页版访问页面  《画加》约稿流程  Yandex世界探索 最新官方免登录入口全知道  C#解析并修改XML后保存 如何确保格式与编码的正确性  C++ priority_queue怎么用_C++优先队列底层实现与自定义比较器  MongoDB聚合管道:高效统计列表中各项的文档数量  PHP魔术方法__set与__isset:设计考量、性能权衡与静态分析的视角  mysql中外键约束如何使用_mysql FOREIGN KEY操作  b站怎么用微信登录_b站微信登录方法  PHP utf8_encode 字符编码转换疑难解析与最佳实践  小红书网页版首页入口 小红书网页版电脑端官方登录链接  在PHP环境中正确加载HTML资源:CSS样式与图片路径指南  CSS布局中意外顶部空白的调试与解决:深入理解padding-top  优化Google Charts Gauge:在数据库无数据时显示默认值  《友玩*》创建群聊方法  掌握Go App Engine项目结构与GOPATH:包管理与导入实践  实现可重用自定义Python Range类  智云Q3和Q2有什么升级_智云Q3与Q2手持云台功能与性能对比分析  包子漫画在线观看入口 包子漫画网正版全集链接  优化2xN网格最大路径和的动态规划算法实践 

 2025-11-08

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.