简介
磁盘空间管理是系统维护中的重要环节。随着数据的不断增长,磁盘空间可能会逐渐被占满,导致系统性能下降甚至崩溃。定期检查和分析磁盘空间使用情况,可以帮助我们及时发现空间不足的问题,并采取相应的措施。本文将介绍一个实用的python脚本——磁盘空间使用报告工具,它可以生成详细的磁盘空间使用报告,帮助用户了解磁盘空间的分布情况。
功能介绍
这个磁盘空间使用报告工具具有以下核心功能:
- 磁盘信息获取:获取系统中所有磁盘分区的总空间、已用空间和可用空间
- 目录大小分析:深入分析指定目录下各子目录和文件的大小分布
- 可视化报告:生成直观的饼图和柱状图展示磁盘空间使用情况
- 详细统计信息:提供文件数量、目录数量、最大文件等统计信息
- 多格式输出:支持文本报告、json数据和图表等多种输出格式
- 过滤功能:可以根据文件类型、大小等条件过滤分析结果
- 定时任务支持:可以集成到定时任务中定期生成报告
- 跨平台兼容:支持windows、linux和macos操作系统
应用场景
这个工具适用于以下场景:
- 系统维护:定期检查服务器磁盘空间使用情况
- 存储优化:识别占用空间较大的目录和文件
- 容量规划:根据历史数据预测存储需求
- 故障排查:定位磁盘空间不足的原因
- 资源审计:审计系统中的大文件和无用文件
- 备份管理:分析备份目录的空间使用情况
报错处理
脚本包含了完善的错误处理机制:
- 路径验证:检查指定目录是否存在且可访问
- 权限检测:检测是否有足够的权限访问目录和文件
- 符号链接处理:正确处理符号链接,避免重复计算或无限循环
- 大文件处理:优化大文件的大小计算过程
- 内存保护:在处理大量文件时防止内存溢出
- 异常捕获:捕获并处理运行过程中可能出现的各种异常
代码实现
import os
import sys
import argparse
import json
from datetime import datetime
import matplotlib.pyplot as plt
from collections import defaultdict
class diskspaceanalyzer:
def __init__(self, path="/"):
self.path = path
self.total_size = 0
self.file_count = 0
self.dir_count = 0
self.largest_files = []
self.dir_sizes = {}
self.file_types = defaultdict(int)
self.errors = []
def get_disk_usage(self):
"""获取磁盘使用情况"""
try:
if os.name == 'nt': # windows
import shutil
total, used, free = shutil.disk_usage(self.path)
else: # unix/linux/macos
statvfs = os.statvfs(self.path)
total = statvfs.f_frsize * statvfs.f_blocks
free = statvfs.f_frsize * statvfs.f_bavail
used = total - free
return {
'total': total,
'used': used,
'free': free,
'percentage': (used / total) * 100 if total > 0 else 0
}
except exception as e:
self.errors.append(f"获取磁盘使用情况失败: {e}")
return none
def format_bytes(self, bytes_value):
"""格式化字节单位"""
for unit in ['b', 'kb', 'mb', 'gb', 'tb']:
if bytes_value < 1024.0:
return f"{bytes_value:.2f} {unit}"
bytes_value /= 1024.0
return f"{bytes_value:.2f} pb"
def get_file_extension(self, filename):
"""获取文件扩展名"""
_, ext = os.path.splitext(filename)
return ext.lower() if ext else 'no_extension'
def analyze_directory(self, max_depth=3, min_size_mb=1):
"""分析目录大小"""
print(f"开始分析目录: {self.path}")
print(f"最大深度: {max_depth}, 最小文件大小: {min_size_mb}mb")
try:
self._walk_directory(self.path, 0, max_depth, min_size_mb * 1024 * 1024)
self._sort_results()
return true
except exception as e:
self.errors.append(f"分析目录时出错: {e}")
return false
def _walk_directory(self, current_path, current_depth, max_depth, min_size):
"""递归遍历目录"""
try:
# 检查是否超过最大深度
if current_depth > max_depth:
return
# 获取目录内容
items = os.listdir(current_path)
dir_size = 0
for item in items:
item_path = os.path.join(current_path, item)
try:
# 跳过隐藏文件和目录
if item.startswith('.'):
continue
# 获取文件/目录信息
stat_info = os.stat(item_path)
if os.path.isfile(item_path):
# 处理文件
file_size = stat_info.st_size
dir_size += file_size
self.file_count += 1
# 记录大于最小大小的文件
if file_size >= min_size:
self.largest_files.append({
'path': item_path,
'size': file_size,
'modified': datetime.fromtimestamp(stat_info.st_mtime)
})
# 统计文件类型
ext = self.get_file_extension(item)
self.file_types[ext] += file_size
elif os.path.isdir(item_path):
# 处理目录
self.dir_count += 1
subdir_size = self._walk_directory(item_path, current_depth + 1, max_depth, min_size)
dir_size += subdir_size
except permissionerror:
self.errors.append(f"权限不足: {item_path}")
except exception as e:
self.errors.append(f"处理 {item_path} 时出错: {e}")
# 记录当前目录大小
self.dir_sizes[current_path] = dir_size
return dir_size
except permissionerror:
self.errors.append(f"权限不足,无法访问目录: {current_path}")
return 0
except exception as e:
self.errors.append(f"遍历目录 {current_path} 时出错: {e}")
return 0
def _sort_results(self):
"""对结果进行排序"""
# 按大小排序目录
self.dir_sizes = dict(sorted(self.dir_sizes.items(), key=lambda x: x[1], reverse=true))
# 按大小排序文件
self.largest_files.sort(key=lambda x: x['size'], reverse=true)
# 按大小排序文件类型
self.file_types = dict(sorted(self.file_types.items(), key=lambda x: x[1], reverse=true))
def get_top_directories(self, count=10):
"""获取最大的几个目录"""
return dict(list(self.dir_sizes.items())[:count])
def get_top_files(self, count=10):
"""获取最大的几个文件"""
return self.largest_files[:count]
def generate_text_report(self):
"""生成文本报告"""
report = []
report.append("=" * 80)
report.append("磁盘空间使用分析报告")
report.append("=" * 80)
report.append(f"分析时间: {datetime.now().strftime('%y-%m-%d %h:%m:%s')}")
report.append(f"分析路径: {self.path}")
report.append("")
# 磁盘使用情况
disk_usage = self.get_disk_usage()
if disk_usage:
report.append("磁盘使用情况:")
report.append(f" 总空间: {self.format_bytes(disk_usage['total'])}")
report.append(f" 已使用: {self.format_bytes(disk_usage['used'])}")
report.append(f" 可用空间: {self.format_bytes(disk_usage['free'])}")
report.append(f" 使用率: {disk_usage['percentage']:.2f}%")
report.append("")
# 统计信息
report.append("统计信息:")
report.append(f" 文件总数: {self.file_count:,}")
report.append(f" 目录总数: {self.dir_count:,}")
report.append(f" 总大小: {self.format_bytes(sum(self.dir_sizes.values()))}")
report.append("")
# 最大的目录
report.append("最大的目录 (top 10):")
report.append("-" * 50)
top_dirs = self.get_top_directories(10)
for i, (dir_path, size) in enumerate(top_dirs.items(), 1):
# 只显示相对路径
relative_path = os.path.relpath(dir_path, self.path) if dir_path != self.path else "."
report.append(f"{i:2d}. {relative_path:<50} {self.format_bytes(size)}")
report.append("")
# 最大的文件
report.append("最大的文件 (top 10):")
report.append("-" * 50)
top_files = self.get_top_files(10)
for i, file_info in enumerate(top_files, 1):
# 只显示相对路径
relative_path = os.path.relpath(file_info['path'], self.path)
modified_time = file_info['modified'].strftime('%y-%m-%d %h:%m:%s')
report.append(f"{i:2d}. {relative_path:<50} {self.format_bytes(file_info['size'])} ({modified_time})")
report.append("")
# 文件类型统计
report.append("文件类型统计 (top 10):")
report.append("-" * 50)
top_types = dict(list(self.file_types.items())[:10])
for i, (ext, size) in enumerate(top_types.items(), 1):
ext_display = ext if ext else '(无扩展名)'
report.append(f"{i:2d}. {ext_display:<20} {self.format_bytes(size)}")
report.append("")
# 错误信息
if self.errors:
report.append("错误信息:")
report.append("-" * 50)
for error in self.errors[:10]: # 只显示前10个错误
report.append(f" {error}")
if len(self.errors) > 10:
report.append(f" ... 还有 {len(self.errors) - 10} 个错误")
report.append("")
report.append("=" * 80)
return "\n".join(report)
def generate_json_report(self, filename=none):
"""生成json报告"""
report = {
'analysis_time': datetime.now().isoformat(),
'path': self.path,
'disk_usage': self.get_disk_usage(),
'statistics': {
'total_files': self.file_count,
'total_directories': self.dir_count,
'total_size': sum(self.dir_sizes.values())
},
'top_directories': self.get_top_directories(20),
'top_files': [
{
'path': f['path'],
'size': f['size'],
'modified': f['modified'].isoformat()
}
for f in self.get_top_files(20)
],
'file_types': self.file_types,
'errors': self.errors
}
if filename:
try:
with open(filename, 'w', encoding='utf-8') as f:
json.dump(report, f, indent=2, ensure_ascii=false)
print(f"json报告已保存到: {filename}")
return true
except exception as e:
print(f"保存json报告时出错: {e}")
return false
else:
return json.dumps(report, indent=2, ensure_ascii=false)
def generate_charts(self, prefix="disk_analysis"):
"""生成图表"""
try:
# 创建图表目录
chart_dir = f"{prefix}_charts"
if not os.path.exists(chart_dir):
os.makedirs(chart_dir)
# 1. 目录大小饼图
top_dirs = self.get_top_directories(8)
other_size = sum(self.dir_sizes.values()) - sum(top_dirs.values())
if top_dirs:
labels = [os.path.basename(path) if path != self.path else '根目录' for path in top_dirs.keys()]
sizes = list(top_dirs.values())
if other_size > 0:
labels.append('其他')
sizes.append(other_size)
plt.figure(figsize=(10, 8))
plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90)
plt.title('目录大小分布')
plt.axis('equal')
plt.savefig(os.path.join(chart_dir, f'{prefix}_directories.png'),
dpi=300, bbox_inches='tight')
plt.close()
# 2. 文件类型柱状图
top_types = dict(list(self.file_types.items())[:10])
if top_types:
labels = [ext if ext else '(无扩展名)' for ext in top_types.keys()]
sizes = [size / (1024*1024) for size in top_types.values()] # 转换为mb
plt.figure(figsize=(12, 6))
plt.bar(labels, sizes)
plt.title('文件类型大小分布 (mb)')
plt.xlabel('文件类型')
plt.ylabel('大小 (mb)')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig(os.path.join(chart_dir, f'{prefix}_filetypes.png'),
dpi=300, bbox_inches='tight')
plt.close()
# 3. 最大文件柱状图
top_files = self.get_top_files(10)
if top_files:
labels = [os.path.basename(f['path']) for f in top_files]
sizes = [f['size'] / (1024*1024) for f in top_files] # 转换为mb
plt.figure(figsize=(12, 6))
plt.bar(labels, sizes)
plt.title('最大文件大小 (mb)')
plt.xlabel('文件名')
plt.ylabel('大小 (mb)')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig(os.path.join(chart_dir, f'{prefix}_largest_files.png'),
dpi=300, bbox_inches='tight')
plt.close()
print(f"图表已保存到目录: {chart_dir}")
return true
except exception as e:
print(f"生成图表时出错: {e}")
return false
def main():
parser = argparse.argumentparser(description="磁盘空间使用报告工具")
parser.add_argument("path", nargs='?', default=".", help="要分析的目录路径 (默认: 当前目录)")
parser.add_argument("-d", "--depth", type=int, default=3, help="分析深度 (默认: 3)")
parser.add_argument("-s", "--min-size", type=float, default=1.0,
help="最小文件大小(mb) (默认: 1.0)")
parser.add_argument("-o", "--output", help="保存文本报告到文件")
parser.add_argument("-j", "--json", help="保存json报告到文件")
parser.add_argument("-c", "--charts", action="store_true", help="生成图表")
parser.add_argument("--chart-prefix", default="disk_analysis", help="图表文件前缀")
args = parser.parse_args()
# 检查路径是否存在
if not os.path.exists(args.path):
print(f"错误: 路径 '{args.path}' 不存在")
sys.exit(1)
if not os.path.isdir(args.path):
print(f"错误: '{args.path}' 不是一个目录")
sys.exit(1)
try:
analyzer = diskspaceanalyzer(args.path)
# 分析目录
if not analyzer.analyze_directory(args.depth, args.min_size):
print("目录分析失败")
sys.exit(1)
# 生成文本报告
report = analyzer.generate_text_report()
# 输出报告
if args.output:
try:
with open(args.output, 'w', encoding='utf-8') as f:
f.write(report)
print(f"文本报告已保存到: {args.output}")
except exception as e:
print(f"保存文本报告时出错: {e}")
else:
print(report)
# 生成json报告
if args.json:
analyzer.generate_json_report(args.json)
# 生成图表
if args.charts:
analyzer.generate_charts(args.chart_prefix)
except keyboardinterrupt:
print("\n\n用户中断操作")
except exception as e:
print(f"程序执行出错: {e}")
sys.exit(1)
if __name__ == "__main__":
main()
使用方法
基本使用
# 分析当前目录 python disk_space_report.py # 分析指定目录 python disk_space_report.py /path/to/directory # 设置分析深度为5层 python disk_space_report.py /path/to/directory -d 5 # 只分析大于10mb的文件 python disk_space_report.py /path/to/directory -s 10 # 保存报告到文件 python disk_space_report.py /path/to/directory -o report.txt # 生成json报告 python disk_space_report.py /path/to/directory -j report.json # 生成图表 python disk_space_report.py /path/to/directory -c --chart-prefix my_analysis
命令行参数说明
path: 要分析的目录路径,默认为当前目录-d, --depth: 分析深度,默认为3层-s, --min-size: 最小文件大小(mb),默认为1.0mb-o, --output: 保存文本报告到指定文件-j, --json: 保存json报告到指定文件-c, --charts: 生成图表--chart-prefix: 图表文件前缀,默认为"disk_analysis"
使用示例
基本分析:
python disk_space_report.py /home/user
深度分析并保存报告:
python disk_space_report.py /var/log -d 5 -s 0.5 -o log_analysis.txt -j log_analysis.json -c
分析系统根目录:
python disk_space_report.py / -d 2 -s 50 -o system_report.txt
总结
这个磁盘空间使用报告工具提供了一个全面的磁盘空间分析解决方案,能够深入分析目录结构并生成详细的使用报告。它不仅可以显示磁盘的整体使用情况,还能识别占用空间最大的目录和文件,帮助用户优化存储空间。工具支持多种输出格式,包括易于阅读的文本报告、便于程序处理的json数据以及直观的图表,满足不同用户的需求。无论是系统管理员进行日常维护,还是普通用户清理存储空间,这个工具都能提供有价值的帮助。
到此这篇关于python检查与分析磁盘空间使用情况并生成报告的文章就介绍到这了,更多相关python磁盘空间内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论