Files
PythonFile/process_archives.py
2025-10-03 17:36:19 +08:00

232 lines
9.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import zipfile
import shutil
import tempfile
import glob
import subprocess
from pathlib import Path
import threading
from concurrent.futures import ThreadPoolExecutor, as_completed
import time
# 导入可能需要安装的库
import tqdm
import patoolib
# 全局锁用于线程安全的输出和文件操作
print_lock = threading.Lock()
file_operation_lock = threading.Lock()
def safe_print(*args, **kwargs):
"""线程安全的打印函数"""
with print_lock:
print(*args, **kwargs)
def safe_file_operation(operation, *args, **kwargs):
"""线程安全的文件操作函数"""
with file_operation_lock:
return operation(*args, **kwargs)
def extract_archive(archive_path, extract_dir):
"""解压缩文件到指定目录"""
safe_print("正在解压文件...")
if archive_path.lower().endswith('.zip'):
# 使用zipfile处理zip文件可以显示进度条
with zipfile.ZipFile(archive_path, 'r') as zip_ref:
total = len(zip_ref.namelist())
for file in tqdm.tqdm(zip_ref.namelist(), total=total, desc="解压进度"):
zip_ref.extract(file, extract_dir)
else:
# 使用patoolib处理其他类型的压缩文件包括RAR
patoolib.extract_archive(archive_path, outdir=extract_dir)
safe_print("解压完成")
# 如果解压后只有一个文件夹将其内容移到extract_dir
items = os.listdir(extract_dir)
if len(items) == 1 and os.path.isdir(os.path.join(extract_dir, items[0])):
subfolder = os.path.join(extract_dir, items[0])
# 将子文件夹中的所有内容移到extract_dir
for item in os.listdir(subfolder):
shutil.move(os.path.join(subfolder, item), extract_dir)
# 删除空文件夹
os.rmdir(subfolder)
def process_files(directory):
"""处理目录中的文件:删除.bat文件重命名.jar文件"""
safe_print("正在处理文件...")
# 查找所有.bat文件并删除
bat_files = []
for root, _, files in os.walk(directory):
for file in files:
if file.lower().endswith('.bat'):
bat_path = os.path.join(root, file)
bat_files.append(bat_path)
# 使用线程池并行删除.bat文件
if bat_files:
def safe_remove_file(file_path):
"""安全删除文件"""
try:
safe_file_operation(os.remove, file_path)
return True
except Exception as e:
safe_print(f"删除文件 {file_path} 时出错: {e}")
return False
with ThreadPoolExecutor(max_workers=4) as executor:
futures = [executor.submit(safe_remove_file, bat_file) for bat_file in bat_files]
successful_deletions = 0
for future in tqdm.tqdm(as_completed(futures), total=len(futures), desc="删除.bat文件"):
if future.result():
successful_deletions += 1
safe_print(f"成功删除 {successful_deletions}/{len(bat_files)} 个.bat文件")
else:
safe_print("未找到需要删除的.bat文件")
# 查找所有.jar文件
jar_files = []
for root, _, files in os.walk(directory):
for file in files:
if file.lower().endswith('.jar'):
jar_path = os.path.join(root, file)
jar_files.append(jar_path)
# 处理.jar文件
if jar_files:
for jar_file in tqdm.tqdm(jar_files, desc="处理.jar文件"):
dir_path = os.path.dirname(jar_file)
# 检查是否存在fabric-server-launch.jar和server.jar
if os.path.basename(jar_file).lower() == 'fabric-server-launch.jar':
server_jar = os.path.join(dir_path, 'server.jar')
if os.path.exists(server_jar):
# 将server.jar重命名为ser.jar
ser_jar = os.path.join(dir_path, 'ser.jar')
safe_file_operation(shutil.move, server_jar, ser_jar)
# 将fabric-server-launch.jar重命名为server.jar
safe_file_operation(shutil.move, jar_file, os.path.join(dir_path, 'server.jar'))
# 如果是普通的jar文件且不是server.jar或ser.jar则重命名为server.jar
elif os.path.basename(jar_file).lower() != 'server.jar' and os.path.basename(jar_file).lower() != 'ser.jar':
# 检查目录中是否已存在server.jar
server_jar = os.path.join(dir_path, 'server.jar')
if not os.path.exists(server_jar):
safe_file_operation(shutil.move, jar_file, server_jar)
else:
safe_print("未找到需要处理的.jar文件")
def compress_directory(source_dir, output_path):
"""将目录压缩为zip文件确保解压后直接是文件而不是文件夹"""
safe_print("正在压缩文件...")
with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
# 获取要压缩的文件列表
file_paths = []
for root, dirs, files in os.walk(source_dir):
for file in files:
file_path = os.path.join(root, file)
file_paths.append(file_path)
# 显示压缩进度
for file in tqdm.tqdm(file_paths, desc="压缩进度"):
# 计算相对路径,确保解压后不会有额外的目录层级
# 获取文件相对于source_dir的路径
rel_path = os.path.relpath(file, source_dir)
# 如果文件在子文件夹中,我们需要保留子文件夹结构,但去掉最外层文件夹
# 例如,如果文件在 temp_dir/folder1/file.txt我们希望在zip中存储为 folder1/file.txt
# 如果文件在 temp_dir/file.txt我们希望在zip中存储为 file.txt
zipf.write(file, rel_path)
def process_single_archive(archive_path, current_dir, index, total):
"""处理单个压缩文件的函数"""
safe_print(f"\n[线程 {threading.current_thread().name}] 处理第 {index+1}/{total} 个压缩文件: {os.path.basename(archive_path)}")
try:
# 创建临时目录用于解压
with tempfile.TemporaryDirectory() as temp_dir:
# 解压文件
try:
extract_archive(archive_path, temp_dir)
except Exception as e:
safe_print(f"解压失败: {e}")
return False
# 处理文件
process_files(temp_dir)
# 确保successzip目录存在
success_dir = os.path.join(current_dir, 'successzip')
if not os.path.exists(success_dir):
safe_file_operation(os.makedirs, success_dir, exist_ok=True)
# 创建新的压缩文件名,使用"cjsyun-"前缀保存到successzip文件夹
processed_archive = os.path.join(success_dir, f"cjsyun-{os.path.basename(archive_path)}")
if processed_archive.lower().endswith('.rar'):
processed_archive = processed_archive[:-4] + '.zip' # 将RAR转换为ZIP
# 压缩处理后的文件
compress_directory(temp_dir, processed_archive)
safe_print(f"[线程 {threading.current_thread().name}] 处理完成: {os.path.basename(processed_archive)}")
return True
except Exception as e:
safe_print(f"处理文件时出错: {e}")
return False
def main():
# 获取当前目录下的所有压缩文件
current_dir = os.path.dirname(os.path.abspath(__file__))
archives = []
for ext in ['*.zip', '*.rar']:
archives.extend(glob.glob(os.path.join(current_dir, ext)))
if not archives:
safe_print("当前目录下没有找到压缩文件")
return
safe_print(f"找到 {len(archives)} 个压缩文件")
# 确定线程数量最多使用4个线程但不超过文件数量
max_workers = min(4, len(archives))
safe_print(f"使用 {max_workers} 个线程并行处理")
start_time = time.time()
# 使用线程池并行处理压缩文件
with ThreadPoolExecutor(max_workers=max_workers, thread_name_prefix="Archive") as executor:
# 提交所有任务
futures = []
for i, archive_path in enumerate(archives):
future = executor.submit(process_single_archive, archive_path, current_dir, i, len(archives))
futures.append(future)
# 等待所有任务完成并收集结果
successful = 0
failed = 0
for future in as_completed(futures):
try:
result = future.result()
if result:
successful += 1
else:
failed += 1
except Exception as e:
safe_print(f"任务执行出错: {e}")
failed += 1
end_time = time.time()
total_time = end_time - start_time
safe_print(f"\n处理完成!")
safe_print(f"成功处理: {successful} 个文件")
safe_print(f"处理失败: {failed} 个文件")
safe_print(f"总耗时: {total_time:.2f}")
safe_print(f"平均每个文件: {total_time/len(archives):.2f}")
if __name__ == "__main__":
main()