如何用Python检测Windows上的按需下载(稀疏)文件?
如何用Python检测Windows上的按需下载(稀疏)文件?
嗨Vladimir,你碰到的这种文件其实是Windows里的稀疏文件——Dropbox的按需下载功能就是用这种机制:文件目录里显示的是完整的逻辑大小,但实际磁盘上只存储了已经下载的部分。当你卸载Dropbox后,这些文件就只剩占位标记,实际磁盘占用为0字节。
你提到用os.path.getsize()或os.stat()只能拿到逻辑大小,这很正常,因为这些Python标准库函数返回的是文件“应该有”的大小,不是实际在磁盘上占的空间。要获取真实的磁盘占用,我们需要调用Windows系统API,这里给你两种可行的方案:
方法一:使用pywin32库(简单易读)
pywin32是专门用于Windows系统交互的Python库,能方便调用各类Windows API。
步骤1:安装pywin32
先通过pip安装库:
pip install pywin32
步骤2:编写检测函数
这个函数会获取文件实际在磁盘上分配的空间(也就是你在属性里看到的“Size on disk”):
import win32file from win32file import FILE_STANDARD_INFO def get_size_on_disk(file_path): try: # 打开文件获取句柄 handle = win32file.CreateFile( file_path, win32file.GENERIC_READ, win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE, None, win32file.OPEN_EXISTING, 0, None ) # 获取文件标准信息,其中包含实际磁盘分配大小 file_info = win32file.GetFileInformationByHandleEx(handle, FILE_STANDARD_INFO) win32file.CloseHandle(handle) # 返回实际占用的字节数 return file_info['AllocationSize'] except Exception as e: print(f"处理文件 {file_path} 时出错: {e}") return -1
方法二:使用ctypes(无需额外安装库)
如果你不想装第三方库,可以用Python内置的ctypes直接调用Windows内核API,实现同样的功能:
import ctypes from ctypes import wintypes # 加载Windows内核库 kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) # 定义存储文件标准信息的结构 class FILE_STANDARD_INFO(ctypes.Structure): _fields_ = [ ('AllocationSize', wintypes.LARGE_INTEGER), ('EndOfFile', wintypes.LARGE_INTEGER), ('NumberOfLinks', wintypes.DWORD), ('DeletePending', wintypes.BOOL), ('Directory', wintypes.BOOL) ] # 定义API函数的参数和返回值类型 kernel32.CreateFileW.argtypes = [ wintypes.LPCWSTR, wintypes.DWORD, wintypes.DWORD, wintypes.LPVOID, wintypes.DWORD, wintypes.DWORD, wintypes.HANDLE ] kernel32.CreateFileW.restype = wintypes.HANDLE kernel32.GetFileInformationByHandleEx.argtypes = [ wintypes.HANDLE, wintypes.DWORD, wintypes.LPVOID, wintypes.DWORD ] kernel32.GetFileInformationByHandleEx.restype = wintypes.BOOL kernel32.CloseHandle.argtypes = [wintypes.HANDLE] kernel32.CloseHandle.restype = wintypes.BOOL def get_size_on_disk_ctypes(file_path): # 打开文件 handle = kernel32.CreateFileW( file_path, 0x80000000, # GENERIC_READ 0x00000001 | 0x00000002, # FILE_SHARE_READ | FILE_SHARE_WRITE None, 3, # OPEN_EXISTING 0x80, # FILE_ATTRIBUTE_NORMAL None ) if handle == wintypes.HANDLE(-1).value: raise ctypes.WinError(ctypes.get_last_error()) try: # 获取文件实际占用信息 file_info = FILE_STANDARD_INFO() buf_size = ctypes.sizeof(file_info) if not kernel32.GetFileInformationByHandleEx( handle, 0, # 0对应FileStandardInfo类型 ctypes.byref(file_info), buf_size ): raise ctypes.WinError(ctypes.get_last_error()) # 返回实际磁盘占用字节数 return file_info.AllocationSize.QuadPart finally: # 确保关闭文件句柄 kernel32.CloseHandle(handle)
批量检测并删除目标文件
有了上面的检测函数,你可以遍历目标文件夹,找出所有实际磁盘占用为0的文件并删除:
import os def clean_zero_disk_space_files(target_folder): for root, _, files in os.walk(target_folder): for filename in files: file_path = os.path.join(root, filename) try: # 这里可以替换成你用的函数:get_size_on_disk 或 get_size_on_disk_ctypes disk_size = get_size_on_disk_ctypes(file_path) if disk_size == 0: print(f"即将删除: {file_path}") # os.remove(file_path) # 测试确认后再取消注释这行 except Exception as e: print(f"跳过文件 {file_path}: {e}") # 替换成你要清理的文件夹路径 clean_zero_disk_space_files(r"C:\Your\Dropbox\遗留文件夹路径")
注意事项
- 先测试再删除:建议先保留
os.remove的注释,只打印文件路径,确认都是你要删除的Dropbox占位文件后再执行删除操作。 - 权限问题:如果目标文件夹在系统保护目录(比如C:\Program Files),可能需要以管理员身份运行Python脚本。
备注:内容来源于stack exchange,提问作者Vladimir Buzalka
相关产品推荐
相关产品推荐

