编辑代码

<?php 
//JSRUN引擎2.0,支持多达30种语言在线运行,全仿真在线交互输入输出。 
echo 'Hello world       -  php.jsrun.net';
import os
import shutil
import platform
import time
import schedule
import logging
from typing import List, Tuple

# 配置日志记录
logging.basicConfig(
    filename='cleaner.log',
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

class SystemCleaner:
    def __init__(self):
        self.system_os = platform.system()
        self.logger = logging.getLogger(__name__)
        self.safe_mode = True  # 安全模式默认开启,只显示将要删除的文件
        self.total_freed = 0  # 总共释放的空间(字节)

        # 定义各系统需要清理的路径和文件类型
        self.clean_targets = {
            'Windows': [
                (os.environ.get('TEMP', r'C:\Windows\Temp'), ['*.tmp', '*.log', '*.bak']),
                (os.environ.get('LOCALAPPDATA', r'C:\Users\*\AppData\Local\Temp'), ['*']),
                (os.path.expanduser('~\\AppData\\Local\\Microsoft\\Windows\\INetCache'), ['*']),
            ],
            'Darwin': [  # macOS
                ('/Library/Caches', ['*']),
                (os.path.expanduser('~/Library/Caches'), ['*']),
                (os.path.expanduser('~/Library/Logs'), ['*.log']),
                ('/private/var/folders', ['*']),
            ],
            'Linux': [
                ('/var/tmp', ['*']),
                ('/var/log', ['*.log']),
                (os.path.expanduser('~/.cache'), ['*']),
                (os.path.expanduser('~/Downloads'), ['*.tmp']),
            ]
        }

    def get_clean_list(self) -> List[Tuple[str, List[str]]]:
        """获取当前系统的清理目标列表"""
        return self.clean_targets.get(self.system_os, [])

    def safe_delete(self, path: str) -> None:
        """安全删除文件/目录"""
        try:
            if os.path.isfile(path):
                os.remove(path)
                self.logger.info(f"Deleted file: {path}")
                self.total_freed += os.path.getsize(path)
            elif os.path.isdir(path):
                shutil.rmtree(path)
                self.logger.info(f"Deleted directory: {path}")
                # 计算目录大小需要额外处理,这里简略处理
        except Exception as e:
            self.logger.error(f"Error deleting {path}: {str(e)}", exc_info=True)

    def scan_and_clean(self, dry_run=True) -> None:
        """扫描并清理垃圾文件"""
        self.logger.info(f"Starting {'dry run' if dry_run else 'actual'} cleaning")
        print(f"\n{' Dry Run Mode ' if dry_run else ' Cleaning Mode ':=^50}")

        for target, patterns in self.get_clean_list():
            target = os.path.expandvars(target)  # 展开环境变量
            try:
                # 处理通配符路径(如Windows的AppData用户路径)
                if '*' in target:
                    import glob
                    expanded_paths = glob.glob(target)
                    if not expanded_paths:
                        continue
                else:
                    expanded_paths = [target]

                for path in expanded_paths:
                    if not os.path.exists(path):
                        continue

                    # 处理不同文件模式
                    for pattern in patterns:
                        for root, dirs, files in os.walk(path):
                            for f in files:
                                file_path = os.path.join(root, f)
                                if self.should_delete(file_path, pattern):
                                    print(f"Found: {file_path}")
                                    if not dry_run:
                                        self.safe_delete(file_path)

            except Exception as e:
                self.logger.error(f"Error processing {target}: {str(e)}", exc_info=True)

        print(f"\nTotal space to free: {self.format_size(self.total_freed)}")
        self.logger.info(f"Cleaning completed. Freed {self.format_size(self.total_freed)}")

    @staticmethod
    def should_delete(file_path: str, pattern: str) -> bool:
        """判断文件是否符合删除条件"""
        filename = os.path.basename(file_path)
        return (
            filename.endswith('.tmp') or
            filename.startswith('~$') or
            filename == 'Thumbs.db' or
            filename.endswith('.log') or
            filename == 'desktop.ini' or
            filename.endswith('.cache') or
            filename.endswith('.bak') or
            filename.endswith('.dmp') or
            (pattern == '*' or filename.endswith(pattern[1:]))
        )

    @staticmethod
    def format_size(size_bytes: int) -> str:
        """格式化存储空间大小"""
        for unit in ['B', 'KB', 'MB', 'GB']:
            if size_bytes < 1024.0:
                return f"{size_bytes:.2f} {unit}"
            size_bytes /= 1024.0
        return f"{size_bytes:.2f} TB"

    def run_scheduled_clean(self) -> None:
        """运行定时清理任务"""
        schedule.every().day.at("02:00").do(self.scan_and_clean, dry_run=False)
        print("Scheduler started. Will run daily at 2:00 AM")
        
        while True:
            schedule.run_pending()
            time.sleep(60)

if __name__ == "__main__":
    cleaner = SystemCleaner()
    try:
        # 首次运行使用安全模式(只显示不删除)
        cleaner.scan_and_clean(dry_run=True)
        
        # 用户确认后执行实际清理
        if input("\nProceed with actual cleaning? (y/n): ").lower() == 'y':
            cleaner.safe_mode = False
            cleaner.scan_and_clean(dry_run=False)
            
        # 是否设置定时任务
        if input("\nSchedule daily cleaning at 12:00 AM? (y/n): ").lower() == 'y':
            cleaner.run_scheduled_clean()
            
    except KeyboardInterrupt:
        print("\nOperation cancelled by user.")
        logging.info("User cancelled the operation")
    except Exception as e:
        logging.critical(f"Critical error: {str(e)}", exc_info=True)
        print(f"An error occurred: {str(e)}. Check cleaner.log for details.")