第三方管家软件如何实现强制删除文件或解除占用

查看 26|回复 2
作者:骑狗的猴子   
个人对一个问题比较好奇,就是一些软件是如何实现删除被占用的文件夹或者文件的,如火绒或360腾讯管家等一类的管家软件,就可以对一个被占用的文件夹进行占用解除或强制删除。
也问过AI了给的回复是 CMD的命令 好几种命令 或者 推荐第三方的工具。
但是个人感觉不是命令进行删除的,具体是什么方式在百度上一番搜索也没有找到,所以在此问问各位大佬看看能不能知道是什么方式实现的。

管家, 第三方

kerolove   

需要涉及系统进程管理、文件操作、注册表操作等多个方面。
import os
import sys
import subprocess
import winreg
import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
import psutil
import shutil
from pathlib import Path
class UninstallerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("软件卸载工具")
        self.root.geometry("800x600")
        
        # 创建主框架
        self.main_frame = ttk.Frame(root, padding="10")
        self.main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建软件列表区域
        ttk.Label(self.main_frame, text="已安装软件列表:").grid(row=0, column=0, sticky=tk.W, pady=5)
        self.software_listbox = tk.Listbox(self.main_frame, width=70, height=20)
        self.software_listbox.grid(row=1, column=0, sticky=(tk.W, tk.E), pady=5)
        self.software_listbox.bind('>', self.on_software_select)
        
        # 创建按钮区域
        self.button_frame = ttk.Frame(self.main_frame)
        self.button_frame.grid(row=2, column=0, sticky=(tk.W, tk.E), pady=5)
        
        ttk.Button(self.button_frame, text="刷新列表", command=self.refresh_software_list).pack(side=tk.LEFT, padx=5)
        ttk.Button(self.button_frame, text="卸载所选软件", command=self.uninstall_selected).pack(side=tk.LEFT, padx=5)
        ttk.Button(self.button_frame, text="强制删除", command=self.force_delete).pack(side=tk.LEFT, padx=5)
        ttk.Button(self.button_frame, text="扫描残留", command=self.scan_for_leftovers).pack(side=tk.LEFT, padx=5)
        
        # 创建日志区域
        ttk.Label(self.main_frame, text="操作日志:").grid(row=3, column=0, sticky=tk.W, pady=5)
        self.log_text = scrolledtext.ScrolledText(self.main_frame, width=70, height=10)
        self.log_text.grid(row=4, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5)
        
        # 初始化软件列表
        self.refresh_software_list()
   
    def log(self, message):
        """添加日志到日志区域"""
        self.log_text.insert(tk.END, message + "\n")
        self.log_text.see(tk.END)
   
    def refresh_software_list(self):
        """刷新已安装软件列表"""
        self.log("正在获取已安装软件列表...")
        self.software_listbox.delete(0, tk.END)
        self.software_dict = self.get_installed_software()
        
        for name, info in self.software_dict.items():
            display_text = f"{name} - {info.get('Version', '未知版本')}"
            self.software_listbox.insert(tk.END, display_text)
            self.software_listbox.itemconfig(self.software_listbox.size() - 1,
                                           fg="blue" if info.get('UninstallString') else "red")
        
        self.log(f"已获取 {len(self.software_dict)} 个软件信息")
   
    def get_installed_software(self):
        """获取Windows注册表中已安装软件的信息"""
        software = {}
        keys = [
            r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
            r"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
        ]
        
        for key in keys:
            try:
                with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key) as reg_key:
                    i = 0
                    while True:
                        try:
                            subkey_name = winreg.EnumKey(reg_key, i)
                            with winreg.OpenKey(reg_key, subkey_name) as subkey:
                                try:
                                    display_name = winreg.QueryValueEx(subkey, "DisplayName")[0]
                                    software_info = {}
                                    
                                    for value_name in ["DisplayVersion", "Publisher", "InstallLocation", "UninstallString"]:
                                        try:
                                            software_info[value_name] = winreg.QueryValueEx(subkey, value_name)[0]
                                        except (FileNotFoundError, OSError):
                                            pass
                                    
                                    software[display_name] = {
                                        "Version": software_info.get("DisplayVersion", "未知版本"),
                                        "Publisher": software_info.get("Publisher", "未知发布者"),
                                        "InstallLocation": software_info.get("InstallLocation", ""),
                                        "UninstallString": software_info.get("UninstallString", "")
                                    }
                                except (FileNotFoundError, OSError):
                                    pass
                            i += 1
                        except OSError:
                            break
            except (FileNotFoundError, OSError):
                pass
        
        return software
   
    def on_software_select(self, event):
        """处理软件选择事件"""
        selection = self.software_listbox.curselection()
        if not selection:
            return
        
        selected_text = self.software_listbox.get(selection[0])
        software_name = selected_text.split(" - ")[0]
        
        if software_name in self.software_dict:
            info = self.software_dict[software_name]
            self.current_software = {
                "name": software_name,
                "info": info
            }
   
    def uninstall_selected(self):
        """卸载所选软件"""
        if not hasattr(self, 'current_software'):
            messagebox.showwarning("警告", "请先选择要卸载的软件")
            return
        
        software = self.current_software
        uninstall_string = software["info"].get("UninstallString", "")
        
        if not uninstall_string:
            messagebox.showwarning("警告", f"无法卸载 {software['name']}:没有找到卸载程序")
            return
        
        try:
            self.log(f"正在卸载 {software['name']}...")
            subprocess.run(uninstall_string, shell=True, check=True)
            self.log(f"{software['name']} 卸载程序已启动,请按照提示完成卸载")
            messagebox.showinfo("信息", f"{software['name']} 卸载程序已启动,请按照提示完成卸载")
            self.refresh_software_list()
        except subprocess.CalledProcessError as e:
            self.log(f"卸载失败: {str(e)}")
            messagebox.showerror("错误", f"卸载失败: {str(e)}")
   
    def force_delete(self):
        """强制删除所选软件及其残留文件"""
        if not hasattr(self, 'current_software'):
            messagebox.showwarning("警告", "请先选择要强制删除的软件")
            return
        
        software = self.current_software
        install_location = software["info"].get("InstallLocation", "")
        
        if not install_location or not os.path.exists(install_location):
            messagebox.showwarning("警告", f"无法强制删除 {software['name']}:没有找到安装目录")
            return
        
        if messagebox.askyesno("确认",
                             f"确定要强制删除 {software['name']} 及其所有文件吗?\n"
                             f"位置: {install_location}\n\n"
                             "此操作不可撤销,可能会导致系统不稳定!"):
            try:
                self.log(f"正在强制删除 {software['name']}...")
               
                # 尝试关闭占用该目录的进程
                self.terminate_processes_using_path(install_location)
               
                # 删除文件和目录
                if os.path.isfile(install_location):
                    os.remove(install_location)
                else:
                    shutil.rmtree(install_location)
               
                self.log(f"{software['name']} 已被强制删除")
                messagebox.showinfo("成功", f"{software['name']} 已被强制删除")
                self.refresh_software_list()
            except Exception as e:
                self.log(f"强制删除失败: {str(e)}")
                messagebox.showerror("错误", f"强制删除失败: {str(e)}")
   
    def terminate_processes_using_path(self, path):
        """终止使用指定路径的所有进程"""
        self.log(f"正在查找占用 {path} 的进程...")
        terminated = 0
        
        for proc in psutil.process_iter(['pid', 'name', 'open_files']):
            try:
                for file in proc.info['open_files'] or []:
                    if path.lower() in file.path.lower():
                        self.log(f"找到进程 {proc.info['name']} (PID: {proc.info['pid']}) 占用 {file.path}")
                        try:
                            proc.terminate()
                            self.log(f"已终止进程 {proc.info['name']} (PID: {proc.info['pid']})")
                            terminated += 1
                        except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
                            self.log(f"无法终止进程 {proc.info['name']} (PID: {proc.info['pid']})")
            except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
                pass
        
        self.log(f"共终止 {terminated} 个占用进程")
        return terminated
   
    def scan_for_leftovers(self):
        """扫描软件残留文件和注册表项"""
        if not hasattr(self, 'current_software'):
            messagebox.showwarning("警告", "请先选择要扫描残留的软件")
            return
        
        software = self.current_software
        install_location = software["info"].get("InstallLocation", "")
        
        if not install_location:
            messagebox.showwarning("警告", f"无法扫描 {software['name']} 的残留:没有找到安装目录")
            return
        
        self.log(f"正在扫描 {software['name']} 的残留文件和注册表项...")
        
        # 扫描文件残留
        leftovers = []
        if os.path.exists(install_location):
            for root, dirs, files in os.walk(install_location):
                for file in files:
                    leftovers.append(os.path.join(root, file))
                for dir in dirs:
                    leftovers.append(os.path.join(root, dir))
        
        # 这里应该扫描注册表残留,但为了安全,我们只做演示
        registry_leftovers = self.simulate_registry_scan(software["name"])
        
        # 显示扫描结果
        if leftovers or registry_leftovers:
            self.show_leftovers(software["name"], leftovers, registry_leftovers)
        else:
            self.log(f"未发现 {software['name']} 的残留文件和注册表项")
            messagebox.showinfo("扫描结果", f"未发现 {software['name']} 的残留文件和注册表项")
   
    def simulate_registry_scan(self, software_name):
        """模拟注册表扫描(实际应用中需要适当的注册表操作)"""
        # 注意:实际注册表操作需要谨慎,可能影响系统稳定性
        self.log("注意:出于安全考虑,演示版本不执行实际的注册表扫描")
        return []  # 返回模拟的注册表残留
   
    def show_leftovers(self, software_name, file_leftovers, registry_leftovers):
        """显示扫描到的残留项并提供清理选项"""
        leftovers_window = tk.Toplevel(self.root)
        leftovers_window.title(f"{software_name} 残留项")
        leftovers_window.geometry("600x400")
        
        # 创建残留项列表
        ttk.Label(leftovers_window, text=f"{software_name} 的残留项:").pack(pady=5)
        
        listbox = tk.Listbox(leftovers_window, width=80, height=15)
        listbox.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        for file in file_leftovers:
            listbox.insert(tk.END, f"文件: {file}")
        
        for reg in registry_leftovers:
            listbox.insert(tk.END, f"注册表: {reg}")
        
        # 创建清理按钮
        button_frame = ttk.Frame(leftovers_window)
        button_frame.pack(fill=tk.X, padx=10, pady=10)
        
        ttk.Button(button_frame, text="清理选中项",
                  command=lambda: self.clean_leftovers(listbox, file_leftovers, registry_leftovers)).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="清理全部",
                  command=lambda: self.clean_leftovers(listbox, file_leftovers, registry_leftovers, clean_all=True)).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="关闭", command=leftovers_window.destroy).pack(side=tk.RIGHT, padx=5)
   
    def clean_leftovers(self, listbox, file_leftovers, registry_leftovers, clean_all=False):
        """清理选中的残留项"""
        if clean_all:
            # 清理所有残留项
            selected_indices = list(range(len(file_leftovers) + len(registry_leftovers)))
        else:
            # 清理选中的残留项
            selected_indices = listbox.curselection()
        
        if not selected_indices:
            messagebox.showwarning("警告", "请选择要清理的残留项")
            return
        
        cleaned = 0
        failed = 0
        
        for index in selected_indices:
            if index < len(file_leftovers):
                # 清理文件残留
                file_path = file_leftovers[index]
                try:
                    if os.path.isfile(file_path):
                        os.remove(file_path)
                    else:
                        shutil.rmtree(file_path)
                    cleaned += 1
                    self.log(f"已清理残留文件: {file_path}")
                except Exception as e:
                    failed += 1
                    self.log(f"清理失败: {file_path} - {str(e)}")
            else:
                # 清理注册表残留(模拟)
                reg_index = index - len(file_leftovers)
                if registry_leftovers:
                    reg_key = registry_leftovers[reg_index]
                    self.log(f"注意:演示版本未实际清理注册表项: {reg_key}")
        
        messagebox.showinfo("清理结果",
                          f"清理完成!\n"
                          f"成功清理: {cleaned}\n"
                          f"清理失败: {failed}")
if __name__ == "__main__":
    # 确保中文显示正常
    if sys.platform.startswith('win'):
        import ctypes
        ctypes.windll.shcore.SetProcessDpiAwareness(1)
   
    root = tk.Tk()
    app = UninstallerApp(root)
    root.mainloop()   
kerolove   

import os
import sys
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
import psutil
import shutil
import threading
from pathlib import Path
import win32api
import win32con
import win32process
import pywintypes
class ForceDeleterApp:
    def __init__(self, root):
        self.root = root
        self.root.title("文件强制删除工具")
        self.root.geometry("600x500")
        self.root.resizable(True, True)
        
        # 设置中文字体
        self.setup_fonts()
        
        # 创建主框架
        self.main_frame = ttk.Frame(root, padding="10")
        self.main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建文件选择区域
        ttk.Label(self.main_frame, text="选择要删除的文件或文件夹:").grid(row=0, column=0, sticky=tk.W, pady=5)
        
        self.path_var = tk.StringVar()
        ttk.Entry(self.main_frame, textvariable=self.path_var, width=50).grid(row=1, column=0, sticky=(tk.W, tk.E), pady=5)
        
        ttk.Button(self.main_frame, text="浏览...", command=self.browse_file).grid(row=1, column=1, padx=5, pady=5)
        
        # 创建操作按钮
        button_frame = ttk.Frame(self.main_frame)
        button_frame.grid(row=2, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=10)
        
        ttk.Button(button_frame, text="分析文件", command=self.analyze_file).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="强制删除", command=self.force_delete, state=tk.DISABLED).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="粉碎文件", command=self.shred_file, state=tk.DISABLED).pack(side=tk.LEFT, padx=5)
        
        # 创建进程列表区域
        ttk.Label(self.main_frame, text="占用进程列表:").grid(row=3, column=0, sticky=tk.W, pady=5)
        
        self.process_tree = ttk.Treeview(self.main_frame, columns=("pid", "name", "path"), show="headings")
        self.process_tree.heading("pid", text="PID")
        self.process_tree.heading("name", text="进程名称")
        self.process_tree.heading("path", text="进程路径")
        
        self.process_tree.column("pid", width=80, anchor=tk.CENTER)
        self.process_tree.column("name", width=150)
        self.process_tree.column("path", width=300)
        
        self.process_tree.grid(row=4, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5)
        
        # 添加滚动条
        scrollbar = ttk.Scrollbar(self.main_frame, orient=tk.VERTICAL, command=self.process_tree.yview)
        self.process_tree.configure(yscroll=scrollbar.set)
        scrollbar.grid(row=4, column=2, sticky=(tk.N, tk.S))
        
        # 创建日志区域
        ttk.Label(self.main_frame, text="操作日志:").grid(row=5, column=0, sticky=tk.W, pady=5)
        
        self.log_text = scrolledtext.ScrolledText(self.main_frame, width=70, height=8)
        self.log_text.grid(row=6, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5)
        
        # 配置列和行的权重,使其可伸缩
        self.main_frame.columnconfigure(0, weight=1)
        self.main_frame.rowconfigure(4, weight=1)
        self.main_frame.rowconfigure(6, weight=1)
        
        # 初始化变量
        self.selected_path = ""
        self.occupying_processes = []
        
        # 设置样式
        self.setup_styles()
   
    def setup_fonts(self):
        """设置中文字体"""
        if sys.platform.startswith('win'):
            default_font = ('Microsoft YaHei UI', 9)
            self.root.option_add('*Font', default_font)
   
    def setup_styles(self):
        """设置界面样式"""
        style = ttk.Style()
        style.configure('TButton', font=('Microsoft YaHei UI', 9))
        style.configure('TLabel', font=('Microsoft YaHei UI', 9))
        style.configure('Treeview', font=('Microsoft YaHei UI', 9))
        style.configure('Treeview.Heading', font=('Microsoft YaHei UI', 9, 'bold'))
   
    def log(self, message):
        """添加日志信息"""
        self.log_text.insert(tk.END, message + "\n")
        self.log_text.see(tk.END)
   
    def browse_file(self):
        """打开文件浏览器选择文件或文件夹"""
        initial_dir = self.path_var.get() if self.path_var.get() else os.path.expanduser("~")
        
        # 让用户选择是文件还是文件夹
        selection_type = tk.simpledialog.askstring("选择类型", "请输入选择类型 (文件=file, 文件夹=folder):",
                                                  initialvalue="file")
        
        if selection_type == "file":
            file_path = filedialog.askopenfilename(initialdir=initial_dir)
            if file_path:
                self.path_var.set(file_path)
                self.selected_path = file_path
        elif selection_type == "folder":
            folder_path = filedialog.askdirectory(initialdir=initial_dir)
            if folder_path:
                self.path_var.set(folder_path)
                self.selected_path = folder_path
   
    def analyze_file(self):
        """分析文件或文件夹,查找占用进程"""
        path = self.path_var.get().strip()
        
        if not path:
            messagebox.showwarning("警告", "请先选择文件或文件夹")
            return
        
        if not os.path.exists(path):
            messagebox.showwarning("警告", f"文件或文件夹不存在: {path}")
            return
        
        self.log(f"正在分析文件: {path}")
        
        # 清空进程列表
        for item in self.process_tree.get_children():
            self.process_tree.delete(item)
        
        # 在新线程中执行分析,避免界面卡顿
        threading.Thread(target=self._analyze_file_thread, args=(path,)).start()
   
    def _analyze_file_thread(self, path):
        """在线程中执行文件分析"""
        try:
            self.occupying_processes = self.find_processes_using_file(path)
            
            if not self.occupying_processes:
                self.root.after(0, lambda: self.log("未发现占用此文件或文件夹的进程"))
                self.root.after(0, lambda: messagebox.showinfo("分析结果", "未发现占用此文件或文件夹的进程"))
                self.root.after(0, lambda: self.update_ui_after_analysis(True))
            else:
                self.root.after(0, lambda: self.log(f"发现 {len(self.occupying_processes)} 个占用进程"))
               
                for proc in self.occupying_processes:
                    self.root.after(0, lambda p=proc: self.process_tree.insert("", tk.END,
                                                                                values=(p['pid'], p['name'], p['path'])))
               
                self.root.after(0, lambda: self.update_ui_after_analysis(True))
        except Exception as e:
            self.root.after(0, lambda: self.log(f"分析过程中出错: {str(e)}"))
            self.root.after(0, lambda: messagebox.showerror("错误", f"分析过程中出错: {str(e)}"))
            self.root.after(0, lambda: self.update_ui_after_analysis(False))
   
    def find_processes_using_file(self, path):
        """查找使用指定文件或文件夹的进程"""
        processes = []
        path = os.path.abspath(path).lower()
        
        # 方法1: 使用psutil库(可能无法检测所有情况)
        try:
            for proc in psutil.process_iter(['pid', 'name', 'open_files']):
                try:
                    for file in proc.info['open_files'] or []:
                        if file.path.lower().startswith(path):
                            processes.append({
                                'pid': proc.info['pid'],
                                'name': proc.info['name'],
                                'path': file.path,
                                'proc_obj': proc
                            })
                except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
                    pass
        except Exception as e:
            self.log(f"psutil方法出错: {str(e)}")
        
        # 方法2: 使用win32 API(更底层,可能检测更多情况)
        try:
            processes.extend(self._find_processes_using_win32(path))
        except Exception as e:
            self.log(f"win32 API方法出错: {str(e)}")
        
        # 去重
        unique_processes = []
        pids = set()
        for proc in processes:
            if proc['pid'] not in pids:
                pids.add(proc['pid'])
                unique_processes.append(proc)
        
        return unique_processes
   
    def _find_processes_using_win32(self, path):
        """使用win32 API查找占用进程"""
        processes = []
        
        # 注意:这是一个简化版的实现,实际Windows系统中查找文件句柄非常复杂
        # 完整实现需要使用NtQuerySystemInformation等未公开API
        
        return processes
   
    def update_ui_after_analysis(self, analysis_successful):
        """分析完成后更新UI状态"""
        if analysis_successful:
            self.root.nametowidget(".!forcedeleterapp.!frame.!button2").config(state=tk.NORMAL)  # 强制删除按钮
            self.root.nametowidget(".!forcedeleterapp.!frame.!button3").config(state=tk.NORMAL)  # 粉碎文件按钮
        else:
            self.root.nametowidget(".!forcedeleterapp.!frame.!button2").config(state=tk.DISABLED)
            self.root.nametowidget(".!forcedeleterapp.!frame.!button3").config(state=tk.DISABLED)
   
    def force_delete(self):
        """强制删除文件或文件夹"""
        path = self.path_var.get().strip()
        
        if not path or not os.path.exists(path):
            messagebox.showwarning("警告", "请先选择有效的文件或文件夹")
            return
        
        if not self.occupying_processes:
            # 如果没有检测到占用进程,直接尝试删除
            result = messagebox.askyesno("确认删除",
                                       f"确定要删除以下文件或文件夹吗?\n\n{path}\n\n"
                                       "此操作不可撤销!")
            if not result:
                return
            
            self.log(f"正在尝试删除: {path}")
            threading.Thread(target=self._delete_file, args=(path, False)).start()
        else:
            # 如果有占用进程,先确认是否终止进程
            proc_names = ", ".join([proc['name'] for proc in self.occupying_processes])
            result = messagebox.askyesno("确认强制删除",
                                       f"以下进程正在占用此文件或文件夹:\n{proc_names}\n\n"
                                       "确定要终止这些进程并强制删除吗?\n\n"
                                       f"文件/文件夹路径: {path}\n\n"
                                       "此操作不可撤销!")
            if not result:
                return
            
            self.log(f"正在终止占用进程并删除: {path}")
            threading.Thread(target=self._force_delete_with_processes, args=(path,)).start()
   
    def _force_delete_with_processes(self, path):
        """带进程终止的强制删除"""
        try:
            # 终止占用进程
            terminated = 0
            for proc in self.occupying_processes:
                try:
                    self.log(f"正在终止进程: {proc['name']} (PID: {proc['pid']})")
                    proc_obj = proc.get('proc_obj')
                    if proc_obj:
                        if proc_obj.status() != psutil.STATUS_ZOMBIE:
                            proc_obj.terminate()
                            proc_obj.wait(timeout=2)  # 等待2秒让进程关闭
                            if proc_obj.status() != psutil.STATUS_ZOMBIE:
                                proc_obj.kill()  # 如果还没关闭,强制杀死
                            terminated += 1
                            self.log(f"成功终止进程: {proc['name']} (PID: {proc['pid']})")
                except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess) as e:
                    self.log(f"无法终止进程 {proc['name']} (PID: {proc['pid']}): {str(e)}")
            
            self.log(f"成功终止 {terminated} 个进程")
            
            # 尝试删除文件或文件夹
            success = self._delete_file(path, True)
            
            if success:
                self.root.after(0, lambda: messagebox.showinfo("成功", f"文件或文件夹已成功删除:\n{path}"))
                self.root.after(0, lambda: self.reset_ui_after_deletion())
            else:
                self.root.after(0, lambda: messagebox.showerror("失败", f"删除文件或文件夹失败:\n{path}"))
        except Exception as e:
            self.root.after(0, lambda: self.log(f"强制删除过程中出错: {str(e)}"))
            self.root.after(0, lambda: messagebox.showerror("错误", f"强制删除过程中出错: {str(e)}"))
   
    def _delete_file(self, path, show_log=True):
        """删除文件或文件夹"""
        try:
            if os.path.isfile(path):
                if show_log:
                    self.log(f"正在删除文件: {path}")
                os.remove(path)
            elif os.path.isdir(path):
                if show_log:
                    self.log(f"正在删除文件夹: {path}")
                shutil.rmtree(path)
            
            if show_log:
                self.log(f"成功删除: {path}")
            return True
        except Exception as e:
            if show_log:
                self.log(f"删除失败: {str(e)}")
            return False
   
    def shred_file(self):
        """粉碎文件,覆盖数据后删除"""
        path = self.path_var.get().strip()
        
        if not path or not os.path.exists(path):
            messagebox.showwarning("警告", "请先选择有效的文件或文件夹")
            return
        
        if os.path.isdir(path):
            messagebox.showwarning("警告", "粉碎文件功能仅适用于文件,不支持文件夹")
            return
        
        result = messagebox.askyesno("确认粉碎",
                                   f"确定要粉碎以下文件吗?\n\n{path}\n\n"
                                   "此操作将覆盖文件数据并彻底删除文件,无法恢复!")
        if not result:
            return
        
        self.log(f"正在粉碎文件: {path}")
        threading.Thread(target=self._shred_file, args=(path,)).start()
   
    def _shred_file(self, path):
        """实现文件粉碎功能"""
        try:
            # 检查是否为文件
            if not os.path.isfile(path):
                self.root.after(0, lambda: messagebox.showerror("错误", "只能粉碎文件,不能粉碎文件夹"))
                return
            
            file_size = os.path.getsize(path)
            
            # 覆盖文件数据 - 三次写入不同模式的数据
            with open(path, 'rb+') as f:
                # 第一次写入:全0
                self.log("正在执行第一次数据覆盖...")
                f.seek(0)
                f.write(b'\x00' * file_size)
               
                # 第二次写入:全1
                self.log("正在执行第二次数据覆盖...")
                f.seek(0)
                f.write(b'\xFF' * file_size)
               
                # 第三次写入:随机数据
                self.log("正在执行第三次数据覆盖...")
                f.seek(0)
                import random
                random_data = bytes([random.randint(0, 255) for _ in range(file_size)])
                f.write(random_data)
            
            # 最后删除文件
            os.remove(path)
            
            self.root.after(0, lambda: self.log(f"文件已成功粉碎: {path}"))
            self.root.after(0, lambda: messagebox.showinfo("成功", f"文件已成功粉碎:\n{path}"))
            self.root.after(0, lambda: self.reset_ui_after_deletion())
        except Exception as e:
            self.root.after(0, lambda: self.log(f"粉碎文件过程中出错: {str(e)}"))
            self.root.after(0, lambda: messagebox.showerror("错误", f"粉碎文件过程中出错: {str(e)}"))
   
    def reset_ui_after_deletion(self):
        """删除操作完成后重置UI"""
        self.path_var.set("")
        self.selected_path = ""
        self.occupying_processes = []
        
        # 清空进程列表
        for item in self.process_tree.get_children():
            self.process_tree.delete(item)
        
        # 禁用操作按钮
        self.root.nametowidget(".!forcedeleterapp.!frame.!button2").config(state=tk.DISABLED)  # 强制删除按钮
        self.root.nametowidget(".!forcedeleterapp.!frame.!button3").config(state=tk.DISABLED)  # 粉碎文件按钮
if __name__ == "__main__":
    root = tk.Tk()
    app = ForceDeleterApp(root)
    root.mainloop()
您需要登录后才可以回帖 登录 | 立即注册

返回顶部