- 查看磁盘占用情况,从小到大排序
du --max-depth=1 -h | sort -h
- 将当前目录下的内容全部打包
tar -cvf download.tar .
- 划定基线的打包程序 tar.py
#!/usr/bin/env python3
"""
按大小过滤的打包脚本
用法: python tar.py [--max=200] [--path=path/] [--zip]
功能: 将目标目录打包为 tar 或 tar.gz,如果指定了 --max,则排除单个文件大小超过该阈值的文件。
"""
import os
import sys
import tarfile
import argparse
from pathlib import Path
# 尝试导入 tqdm,如果失败则使用自定义简单进度条
try:
from tqdm import tqdm
HAS_TQDM = True
except ImportError:
HAS_TQDM = False
# 自定义简单进度条
def simple_progress_bar(iterable, total, desc="进度"):
"""
简单的文本进度条实现
"""
bar_len = 40
sys.stdout.write(f"{desc}: 0%")
sys.stdout.flush()
for i, item in enumerate(iterable, 1):
yield item
if i % max(1, total // 100) == 0 or i == total:
percent = i / total
filled = int(bar_len * percent)
bar = '█' * filled + '-' * (bar_len - filled)
sys.stdout.write(f'\r{desc}: |{bar}| {percent*100:.1f}% ({i}/{total})')
sys.stdout.flush()
sys.stdout.write('\n')
def get_total_files_and_size(src_dir):
"""
遍历目录,统计总文件数和总大小(用于进度条估算)
返回: (总文件数, 总字节数)
"""
total_files = 0
total_size = 0
for root, dirs, files in os.walk(src_dir):
for file in files:
file_path = os.path.join(root, file)
try:
total_size += os.path.getsize(file_path)
total_files += 1
except OSError:
pass
return total_files, total_size
def should_include(file_path, max_size_bytes):
"""
判断文件是否应该被打包。
返回 True 表示打包,False 表示跳过。
"""
if os.path.isdir(file_path):
return True
try:
file_size = os.path.getsize(file_path)
if max_size_bytes is not None and file_size > max_size_bytes:
return False
except OSError:
return False
return True
def main():
parser = argparse.ArgumentParser(
description="打包目录,可选择跳过超过指定大小的文件"
)
parser.add_argument(
"--max",
type=int,
default=None,
help="文件大小阈值,单位 MB,例如 200 表示 200MB。缺省时不限制大小。"
)
parser.add_argument(
"--path",
type=str,
default=".",
help="要打包的目标目录路径,缺省为当前目录"
)
parser.add_argument(
"--zip",
"-z",
action="store_true",
help="开启 gzip 压缩,输出 .tar.gz 格式 (默认输出 .tar,不压缩)"
)
args = parser.parse_args()
src_dir = os.path.abspath(args.path)
if not os.path.isdir(src_dir):
print(f"错误: 路径 '{src_dir}' 不是有效的目录")
sys.exit(1)
max_bytes = args.max * 1024 * 1024 if args.max is not None else None
dir_name = os.path.basename(src_dir.rstrip('/\\'))
# 根据是否压缩决定输出文件名和打开模式
if args.zip:
output_filename = f"{dir_name}_filtered.tar.gz" if args.max is not None else f"{dir_name}.tar.gz"
tar_mode = "w:gz" # gzip 压缩
compress_desc = "gzip 压缩"
else:
output_filename = f"{dir_name}_filtered.tar" if args.max is not None else f"{dir_name}.tar"
tar_mode = "w" # 不压缩
compress_desc = "不压缩"
output_path = os.path.join(os.getcwd(), output_filename)
print(f"目标目录: {src_dir}")
if max_bytes is not None:
print(f"阈值: {args.max} MB ({max_bytes} bytes)")
else:
print("阈值: 无限制 (打包所有文件)")
print(f"压缩: {compress_desc}")
print(f"输出文件: {output_path}")
# 统计总文件数和总大小(用于进度条估算)
print("正在扫描目录...")
total_files, total_size = get_total_files_and_size(src_dir)
print(f"总文件数: {total_files}, 总大小: {total_size/(1024*1024):.2f} MB")
skipped_count = 0
skipped_size = 0
try:
with tarfile.open(output_path, tar_mode) as tar:
# 准备文件列表(用于进度条遍历)
file_list = []
for root, dirs, files in os.walk(src_dir):
for file in files:
file_list.append(os.path.join(root, file))
# 根据是否安装 tqdm 选择进度条实现
if HAS_TQDM:
print("使用 tqdm 进度条")
iterator = tqdm(file_list, desc="打包进度", unit="file")
else:
print("使用标准进度条 (提示: 安装 tqdm 获得更美观的进度条: pip install tqdm)")
iterator = simple_progress_bar(file_list, total=len(file_list), desc="打包进度")
for file_path in iterator:
arcname = os.path.relpath(file_path, start=os.path.dirname(src_dir))
if should_include(file_path, max_bytes):
try:
if HAS_TQDM:
iterator.set_postfix_str(f"当前: {os.path.basename(file_path)}")
tar.add(file_path, arcname=arcname)
except Exception as e:
print(f"\n警告: 添加文件失败 {file_path}: {e}")
else:
skipped_count += 1
try:
skipped_size += os.path.getsize(file_path)
except OSError:
pass
print(f"\n打包完成: {output_path}")
if skipped_count > 0:
print(f"跳过了 {skipped_count} 个文件,总计 {skipped_size/(1024*1024):.2f} MB")
except Exception as e:
print(f"打包失败: {e}")
sys.exit(1)
if __name__ == "__main__":
main()
- 文件递归排序 filesize_sort.py
#!/usr/bin/env python3
"""
文件大小排序工具
遍历指定目录,按文件大小从大到小排序并输出路径、大小和累积百分比
用法: python filesize_sort.py [--path=path/] [--top=N] [--reverse]
"""
import os
import sys
import argparse
from pathlib import Path
def human_readable_size(size_bytes):
"""
将字节数转换为人类可读的格式(KB, MB, GB)
返回格式: "1.23 GB"
"""
if size_bytes == 0:
return "0 B"
units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
unit_index = 0
temp = size_bytes
while temp >= 1024 and unit_index < len(units) - 1:
temp /= 1024
unit_index += 1
if unit_index == 0:
return f"{size_bytes} B"
else:
return f"{temp:.2f} {units[unit_index]}"
def get_file_info(src_dir, exclude_dirs=None):
"""
遍历目录,收集所有文件的信息(路径和大小)
"""
if exclude_dirs is None:
exclude_dirs = []
file_list = []
src_dir = os.path.abspath(src_dir)
if not os.path.isdir(src_dir):
print(f"错误: 路径 '{src_dir}' 不是有效的目录")
sys.exit(1)
for root, dirs, files in os.walk(src_dir):
dirs[:] = [d for d in dirs if d not in exclude_dirs]
for file in files:
file_path = os.path.join(root, file)
try:
size = os.path.getsize(file_path)
file_list.append((file_path, size))
except OSError:
print(f"警告: 无法读取文件大小,跳过: {file_path}")
return file_list
def main():
parser = argparse.ArgumentParser(
description="遍历目录,按文件大小排序输出,含累积百分比"
)
parser.add_argument(
"--path",
type=str,
default=".",
help="要遍历的目标目录路径,缺省为当前目录"
)
parser.add_argument(
"--top",
type=int,
default=None,
help="只显示前 N 个最大的文件"
)
parser.add_argument(
"--reverse",
"-r",
action="store_true",
help="按从小到大排序(默认从大到小)"
)
parser.add_argument(
"--exclude",
type=str,
nargs="*",
default=[".git", "__pycache__", "node_modules", ".idea", ".vscode"],
help="要排除的目录名称(空格分隔),缺省排除常见缓存目录"
)
parser.add_argument(
"--bytes",
"-b",
action="store_true",
help="以字节数显示(不转换为 KB/MB/GB)"
)
parser.add_argument(
"--no-percent",
action="store_true",
help="不显示累积百分比列"
)
args = parser.parse_args()
src_dir = os.path.abspath(args.path)
print(f"正在扫描目录: {src_dir}")
print(f"排除目录: {args.exclude if args.exclude else '无'}")
file_list = get_file_info(src_dir, args.exclude)
if not file_list:
print("没有找到任何文件")
return
# 按文件大小排序(默认从大到小)
reverse_sort = not args.reverse
file_list.sort(key=lambda x: x[1], reverse=reverse_sort)
total_size = sum(size for _, size in file_list)
# 如果指定了 --top,只取前 N 个
display_list = file_list[:args.top] if args.top is not None else file_list
print("\n" + "=" * 100)
# 计算列宽
max_path_len = max(len(path) for path, _ in display_list) if display_list else 0
max_path_len = min(max_path_len, 50)
# 根据是否显示百分比决定列头
if args.no_percent:
header = f"{'文件路径':<{max_path_len}} {'大小':>15}"
else:
header = f"{'文件路径':<{max_path_len}} {'大小':>15} {'累积占比':>12}"
print(header)
print("-" * 100)
# 累积大小(从大到小累加)
cumulative_size = 0
for idx, (file_path, size) in enumerate(display_list):
cumulative_size += size
# 显示路径(如果太长则截断)
display_path = file_path if len(file_path) <= max_path_len else "..." + file_path[-(max_path_len-3):]
# 格式化大小
if args.bytes:
size_str = f"{size:,} B"
else:
size_str = human_readable_size(size)
# 计算累积百分比
if args.no_percent:
print(f"{display_path:<{max_path_len}} {size_str:>15}")
else:
cum_percent = (cumulative_size / total_size) * 100 if total_size > 0 else 0
# 如果当前文件是最后一个,百分比应为100%
if idx == len(display_list) - 1:
cum_percent = 100.0
print(f"{display_path:<{max_path_len}} {size_str:>15} {cum_percent:>11.2f}%")
print("-" * 100)
# 统计信息
if args.bytes:
total_str = f"{total_size:,} B"
else:
total_str = human_readable_size(total_size)
displayed_count = len(display_list)
total_count = len(file_list)
if args.top is not None:
print(f"显示: {displayed_count}/{total_count} 个文件, 总大小: {total_str}")
if not args.no_percent and display_list:
# 显示前 N 个文件的占比
top_percent = (cumulative_size / total_size) * 100
print(f"前 {displayed_count} 个文件占总大小的: {top_percent:.2f}%")
else:
print(f"总计: {displayed_count} 个文件, 总大小: {total_str}")
if __name__ == "__main__":
main()