在Python中获取文件的大小4种办法

'# 在Python中获取文件的大小4种办法

一、背景与问题

在开发文件处理系统时,获取文件大小是常见需求。例如:

  • 上传文件时限制大小
  • 日志文件清理时判断是否超过阈值
  • 文件传输时计算传输量
  • 系统监控时统计磁盘使用情况

但不同场景下需要不同方法,本文将深入探讨四种实现方案,涵盖文件系统元数据、文件对象读取、压缩文件处理等场景。

二、基本原理

文件大小获取本质是读取文件系统元数据或实际读取文件内容。不同方法的差异主要体现在:

  1. 文件系统接口:通过os.path或stat模块访问文件系统元数据
  2. 文件读取方式:通过文件对象逐块读取内容
  3. 压缩文件处理:通过zipfile库解析压缩包
  4. 内存映射:通过mmap模块处理大文件

三、环境准备

# 安装依赖(如需处理压缩文件)
pip install python-magic

四、核心实现

方法一:通过文件系统元数据获取(推荐)

import os

def get_file_size(path):
    """
    通过文件系统接口获取文件大小
    支持所有文件系统(包括网络文件系统)
    """
    try:
        return os.path.getsize(path)
    except OSError as e:
        print(f"获取文件大小失败: {e}")
        return -1

关键点解释:

  • os.path.getsize()直接读取文件系统元数据
  • 适用于所有文件系统(本地/网络/压缩包)
  • 无需打开文件,效率最高(O(1)时间复杂度)
  • 需处理文件路径不存在、权限不足等异常

方法二:通过文件对象读取(适用于大文件)

def get_file_size_by_read(path):
    """
    通过文件对象逐块读取计算文件大小
    适用于无法直接读取元数据的场景
    """
    try:
        with open(path, 'rb') as f:
            size = 0
            while True:
                chunk = f.read(65536)  # 每次读取64KB
                if not chunk:
                    break
                size += len(chunk)
            return size
    except IOError as e:
        print(f"读取文件失败: {e}")
        return -1

关键点解释:

  • 通过文件对象读取内容计算总长度
  • 适用于无法直接读取元数据的特殊文件
  • 分块读取避免内存溢出(适合大文件)
  • 需注意文件关闭的异常处理

方法三:处理压缩文件(zip格式)

import zipfile

def get_compressed_file_size(path):
    """
    获取压缩文件中所有文件的总大小
    """
    try:
        with zipfile.ZipFile(path, 'r') as zipf:
            total_size = sum(file_info.file_size for file_info in zipf.infolist())
            return total_size
    except zipfile.BadZipFile as e:
        print(f"压缩文件解析失败: {e}")
        return -1

关键点解释:

  • 通过zipfile模块解析压缩包
  • 直接读取压缩包中的文件信息
  • 不需要解压文件即可获取大小
  • 需处理压缩文件格式错误等异常

方法四:内存映射方式(适用于特殊文件系统)

import mmap

def get_file_size_by_mmap(path):
    """
    通过内存映射获取文件大小
    适用于特殊文件系统(如管道、内存文件)
    """
    try:
        with open(path, 'rb') as f:
            with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as mm:
                return mm.size()
    except (OSError, ValueError) as e:
        print(f"内存映射失败: {e}")
        return -1

关键点解释:

  • 使用mmap模块创建内存映射
  • 适用于特殊文件系统和内存文件
  • 可以直接访问文件内容
  • 需处理内存映射失败等异常

五、完整案例

文件上传校验系统

import os
import zipfile
import magic

class FileValidator:
    def __init__(self, max_size=1024*1024*10):  # 10MB
        self.max_size = max_size

    def validate_file(self, file_path):
        """验证文件大小和格式"""
        try:
            # 获取文件大小
            size = self.get_file_size(file_path)
            if size > self.max_size:
                raise ValueError(f"文件过大: {size} bytes")
            
            # 检查文件类型
            mime = magic.Magic(mime=True)
            file_type = mime.from_file(file_path)
            
            # 检查压缩文件
            if file_type.startswith('application/zip'):
                self.validate_compressed_file(file_path)
            
            return True
        except Exception as e:
            print(f"文件校验失败: {e}")
            return False

    def get_file_size(self, path):
        """统一获取文件大小的方法"""
        # 优先尝试文件系统接口
        try:
            return os.path.getsize(path)
        except Exception as e:
            # 落回文件读取方式
            return self.get_file_size_by_read(path)

    def validate_compressed_file(self, path):
        """验证压缩文件内容"""
        with zipfile.ZipFile(path, 'r') as zipf:
            for file_info in zipf.infolist():
                if file_info.filename == '..':
                    raise ValueError("包含危险路径")
                if file_info.file_size > self.max_size:
                    raise ValueError(f"压缩文件内文件过大: {file_info.file_size} bytes")

关键点说明:

  • 统一的文件大小获取接口
  • 支持多种文件类型
  • 包含安全检查(防止路径遍历)
  • 自动选择最合适的方法

六、源码解析

以get_file_size_by_read方法为例:

def get_file_size_by_read(path):
    try:
        with open(path, 'rb') as f:
            size = 0
            while True:
                chunk = f.read(65536)  # 每次读取64KB
                if not chunk:
                    break
                size += len(chunk)
            return size
    except IOError as e:
        print(f"读取文件失败: {e}")
        return -1

逐行解释:

  1. 使用with语句确保文件正确关闭
  2. open以二进制模式读取文件
  3. 64KB是常见分块大小,平衡内存和性能
  4. 循环读取直到文件末尾
  5. 累加每块的大小
  6. 捕获IO异常并返回错误码

七、进阶使用

多线程处理

from concurrent.futures import ThreadPoolExecutor

def get_files_size_in_parallel(paths):
    """多线程获取多个文件大小"""
    with ThreadPoolExecutor() as executor:
        results = list(executor.map(get_file_size, paths))
    return results

性能优化

  • 对于大量小文件,使用os.path.getsize更高效
  • 对于大文件,使用get_file_size_by_read避免内存占用
  • 对于压缩文件,直接解析zipinfo更高效

八、性能与工程实践

性能对比

方法时间复杂度适用场景内存占用
os.path.getsizeO(1)常规文件极低
文件读取O(n)特殊文件低
zip解析O(1)压缩文件低
mmapO(1)特殊文件系统高

异常处理

  • 文件路径不存在:FileNotFoundError
  • 权限不足:PermissionError
  • 文件过大:MemoryError(需处理内存溢出)

安全考虑

  1. 路径遍历漏洞:../../etc/passwd等危险路径
  2. 压缩包炸弹:大压缩包导致内存溢出
  3. 非法文件格式:恶意文件可能导致解析错误

九、常见问题与踩坑

常见错误

  1. 错误示例:

    with open('file.txt', 'r') as f:
     size = len(f.read())

    问题:读取大文件会占用大量内存

  2. 错误示例:

    os.path.getsize('file.txt')  # 本地文件
    os.path.getsize('http://example.com/file.txt')  # 网络文件

    问题:网络文件无法直接使用os.path.getsize

解决方案

  1. 使用get_file_size_by_read处理大文件
  2. 使用requests获取网络文件大小

    import requests
    def get_remote_file_size(url):
     response = requests.head(url)
     return int(response.headers.get('content-length', 0))

性能陷阱

  • 对于大文件,os.path.getsize比读取文件快100倍以上
  • 压缩文件的file_size是压缩后的大小,不是解压后的实际大小

十、最佳实践

推荐方案

场景推荐方法原因
本地文件os.path.getsize最高效
大文件get_file_size_by_read避免内存问题
压缩文件get_compressed_file_size直接解析
网络文件requests.head轻量级获取

编码规范

  • 使用with语句处理文件
  • 优先使用文件系统接口
  • 对敏感操作添加日志记录
  • 对异常进行详细分类处理

十一、总结

获取文件大小是文件处理系统的基础功能,但不同场景需要不同方法:

  1. 常规文件推荐使用os.path.getsize,它是最高效且最简单的实现
  2. 大文件应使用分块读取的方式避免内存溢出
  3. 压缩文件需要特殊处理,直接解析压缩包信息更高效
  4. 特殊文件系统需要使用内存映射技术

在实际开发中,建议:

  • 对于常规文件处理,统一使用get_file_size接口
  • 对于敏感操作添加安全校验(如路径过滤)
  • 对大文件处理添加性能监控
  • 对网络文件处理使用轻量级获取方式

通过理解不同方法的原理和适用场景,可以更有效地处理文件大小相关的业务需求。

最后修改于:2026年10月06日 04:46

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日