吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 988|回复: 25
收起左侧

[Python 原创] 文件(夹)删除-防数据恢复

  [复制链接]
dzxsl 发表于 2025-4-7 14:12
可通过拖拽、选择方式选择文件或者文件夹进行删除,可有效防止数据被软件恢复。

软件页面

软件页面


源代码.rar (4.07 KB, 下载次数: 16)

编译好的链接:https://pan.baidu.com/s/1kZCRBbWi6F6iD3FWoTVAuA 提取码:52pj
[Python] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
import os
import random
import sys
import threading
import shutil
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, END
from tkinterdnd2 import TkinterDnD, DND_FILES
 
def secure_delete(file_path, passes=3, progress_callback=None):
 
    """
    安全删除文件,通过多次覆盖文件内容防止数据恢复
     
    参数:
        file_path (str): 要删除的文件路径
        passes (int): 覆盖次数(默认3次)
         
    返回:
        bool: 成功返回True,失败返回False
    """
    try:
        if not os.path.isfile(file_path):
            raise ValueError(f"文件 {file_path} 不存在")
 
        file_size = os.path.getsize(file_path)
         
        with open(file_path, 'br+') as f:  # 二进制读写模式
            for pass_num in range(passes):
                # 生成覆盖模式描述
                patterns = [
                    lambda n: os.urandom(n),                # 随机字节
                    lambda n: bytes([0xFF] * n),            # 全1
                    lambda n: bytes([0x00] * n),           # 全0
                    lambda n: bytes([0xAA] * n),            # 1010模式
                    lambda n: bytes([0x55] * n)             # 0101模式
                ]
                pattern = patterns[pass_num % len(patterns)]
 
                f.seek(0)
                 
                # 分块写入以处理大文件
                chunk_size = 1024 * 1024  # 1MB
                written = 0
                while written < file_size:
                    write_size = min(chunk_size, file_size - written)
                    data = pattern(write_size)
                    f.write(data)
                    written += write_size
                    # 添加进度回调(确保在主线程更新)
                    if progress_callback:
                        progress_callback(written, file_size)  # 传入当前写入量和总量
                f.flush()
                os.fsync(f.fileno())  # 确保写入物理介质
 
        # 重命名文件以破坏元数据
        temp_name = None
        for i in range(3):
            try:
                # 在同一目录下创建临时文件
                temp_name = os.path.join(os.path.dirname(file_path), f".{random.randint(0, 9999999999)}.tmp")
                shutil.move(file_path, temp_name)  # 使用 shutil.move 支持跨磁盘驱动器
                break
            except Exception as e:
                print(f"重命名失败: {str(e)}", file=sys.stderr)
                continue
 
        # 最终删除文件
        if temp_name and os.path.exists(temp_name):
            try:
                os.remove(temp_name)
            except Exception as e:
                print(f"删除临时文件失败: {str(e)}", file=sys.stderr)
                return False
        else:
            print("临时文件不存在,可能已被删除", file=sys.stderr)
            return False
         
        return True
 
    except Exception as e:
        print(f"删除失败: {str(e)}", file=sys.stderr)
        return False
 
class SecureDeleterGUI(TkinterDnD.Tk):
    def __init__(self):
        super().__init__()
        self.title("文件(夹)永久删除-防恢复")
        self.geometry("600x400")
        self.configure(bg='#f0f0f0')
         
        # 初始化拖拽区域标识
        self.drop_target_color = '#e0e0e0'
        self.normal_bg_color = '#f0f0f0'
         
        # 创建GUI组件
        self.create_widgets()
        self.abort_flag = False
        # 新增:用于存储所有要删除的文件和文件夹路径
        self.target_paths = []
         
    def create_widgets(self):
        # 拖拽区域提示标签
        self.drop_label = ttk.Label(
            self,
            text="拖拽文件或文件夹至此区域",
            font=('微软雅黑', 14),
            relief='ridge',
            anchor='center'
        )
        self.drop_label.pack(pady=20, padx=40, fill=tk.X)
         
        # 绑定拖拽事件
        self.drop_label.drop_target_register(DND_FILES)
        self.drop_label.dnd_bind('<<Drop>>', self.on_drop)
        self.drop_label.dnd_bind('<<Enter>>', self.on_drag_enter)
        self.drop_label.dnd_bind('<<Leave>>', self.on_drag_leave)
 
        # 进度条
        self.progress = ttk.Progressbar(
            self,
            orient=tk.HORIZONTAL,
            length=400,
            mode='determinate'
        )
        self.progress.pack(pady=15)
 
        # 日志文本框
        self.log_text = tk.Text(
            self,
            height=12,
            wrap=tk.WORD,
            bg='white',
            font=('Consolas', 9)
        )
        self.log_text.pack(pady=10, fill=tk.BOTH, expand=True, padx=20)
 
        # 底部控制按钮
        control_frame = ttk.Frame(self)
        control_frame.pack(pady=10)
         
        ttk.Button(
            control_frame,
            text="选择文件",
            command=self.select_file
        ).grid(row=0, column=0, padx=5)
         
        ttk.Button(
            control_frame,
            text="选择文件夹",
            command=self.select_folder
        ).grid(row=0, column=1, padx=5)
         
        ttk.Button(
            control_frame,
            text="开始删除",
            command=self.start_deletion
        ).grid(row=0, column=2, padx=5)
         
        ttk.Button(
            control_frame,
            text="中止操作",
            command=self.abort_operation
        ).grid(row=0, column=3, padx=5)
 
    def on_drag_enter(self, event):
        """拖拽进入时的视觉效果"""
        self.drop_label.configure(background=self.drop_target_color)
         
    def on_drag_leave(self, event):
        """拖拽离开时恢复颜色"""
        self.drop_label.configure(background=self.normal_bg_color)
         
    def on_drop(self, event):
        """处理拖拽释放事件"""
        self.drop_label.configure(background=self.normal_bg_color)
         
        # 解析拖拽数据
        data = event.data
        paths = self.parse_dropped_paths(data)
         
        if not paths:
            self.log("错误:无效的拖拽内容")
            return
             
        # 目前只处理第一个拖拽项
        valid_paths = []
        for path in paths:
            path = path.strip()
            if os.path.isfile(path) or os.path.isdir(path):
                valid_paths.append(path)
                if os.path.isfile(path):
                    self.log(f"已拖入文件: {path}")
                else:
                    self.log(f"已拖入文件夹: {path}")
            else:
                self.log(f"错误:无效路径 {path}")
 
        # 新增:将有效路径添加到目标路径列表
        self.target_paths.extend(valid_paths)
 
    @staticmethod
    def parse_dropped_paths(data):
        """跨平台解析拖拽路径"""
        # Windows返回格式: {路径1} {路径2}
        if data.startswith('{') and data.endswith('}'):
            return data[1:-1].split('} {')
        # Linux/macOS返回格式: 路径1 路径2 (用空格分隔)
        else:
            return data.split()
 
    # 以下原有方法保持不变(select_file, select_folder, log等)
    # ...(保持与之前版本相同的其他方法)...
    def select_file(self):
        # 修改为支持多选文件
        file_paths = filedialog.askopenfilenames(title="选择要删除的文件")
        if file_paths:
            # 把多个文件路径添加到目标路径列表
            self.target_paths.extend(file_paths)
            for file_path in file_paths:
                self.log(f"已选择文件: {file_path}")
 
    def select_folder(self):
        # 选择选文件夹
        folder_paths = filedialog.askdirectory(title="选择要删除的文件夹")
        if folder_paths:
            # 把多个文件夹路径添加到目标路径列表
            self.target_paths.extend(folder_paths)
            for folder_path in folder_paths:
                self.log(f"已选择文件夹: {folder_path}")
 
    def log(self, message):
        self.log_text.insert(END, message + "\n")
        self.log_text.see(END)
        self.update_idletasks()  # 修改此处:self.update_idletasks()
 
    def start_deletion(self):
        if not self.target_paths:
            messagebox.showwarning("警告", "请先选择文件或文件夹")
            return
 
        confirm = messagebox.askyesno("确认删除",f"即将永久删除以下内容:\n{' '.join(self.target_paths)}\n此操作不可恢复!确认继续?")
        if not confirm:
            return
 
        # 禁用按钮并重置进度条
        self.toggle_controls(False)
        self.abort_flag = False
        self.progress['value'] = 0
 
        # 启动后台线程执行删除
        threading.Thread(target=self.process_deletion, daemon=True).start()
 
    def process_deletion(self):
        try:
            total_items = len(self.target_paths)
            current_item = 0
            for path in self.target_paths:
                if self.abort_flag:
                    self.log("用户中止操作")
                    break
                if os.path.isfile(path):
                    # 修改:传递具体文件路径
                    self.process_single_file(path)
                else:
                    # 修改:传递具体文件夹路径
                    self.process_folder(path)
                current_item += 1
                self.progress['value'] = (current_item / total_items) * 100
        except Exception as e:
            self.log(f"发生错误: {str(e)}")
        finally:
            self.toggle_controls(True)
            # 新增:清空目标路径列表
            self.target_paths = []
 
    def process_single_file(self, file_path):
        # 修改:接收具体文件路径
        self.log(f"开始处理文件: {os.path.basename(file_path)}")
        success = secure_delete(file_path, progress_callback=self.update_progress)
        self.log("文件删除完成" if success else "文件删除失败")
 
    def process_folder(self, folder_path):
        # 修改:接收具体文件夹路径
        total_files = 0
        # 预先统计文件总数
        for root, dirs, files in os.walk(folder_path):
            total_files += len(files)
 
        if total_files == 0:
            self.log("文件夹为空,直接删除该文件夹")
            try:
                # 直接删除空文件夹
                shutil.rmtree(folder_path)
                self.log(f"文件夹 {folder_path} 删除完成")
            except Exception as e:
                self.log(f"删除文件夹 {folder_path} 失败: {str(e)}")
            return
 
        self.log(f"发现 {total_files} 个文件,开始处理...")
 
        current_count = 0
        for root, dirs, files in os.walk(folder_path):
            for filename in files:
                if self.abort_flag:
                    self.log("用户中止操作")
                    return
 
                file_path = os.path.join(root, filename)
                self.log(f"正在处理: {file_path}")
 
                secure_delete(file_path, progress_callback=self.update_progress)
                current_count += 1
                # 更新单个文件夹内文件处理的进度
                self.progress['value'] = (current_count / total_files) * 100
        try:
            # 删除已清空文件的文件夹
            shutil.rmtree(folder_path)
            self.log(f"文件夹 {folder_path} 及其内容删除完成")
            self.log(f"已完成所有文件处理,共删除 {current_count} 个文件")
        except Exception as e:
            self.log(f"删除文件夹 {folder_path} 失败: {str(e)}")
 
         
 
 
    def update_progress(self, current, total):
        def _update():
            if total > 0:
                percent = (current / total) * 100
                self.progress['value'] = percent
        self.after(0, _update)  # 使用 after 确保线程安全
 
    def toggle_controls(self, enabled):
        state = "normal" if enabled else "disabled"
        for child in self.winfo_children():
            if isinstance(child, ttk.Button):
                child['state'] = state
 
    def abort_operation(self):
        self.abort_flag = True
        self.log("正在中止当前操作...")
 
 
if __name__ == "__main__":
    try:
        app = SecureDeleterGUI()
        app.mainloop()
    except ImportError:
        print("错误:需要安装 tkinterdnd2 库")
        print("安装命令: pip install tkinterdnd2")

免费评分

参与人数 3吾爱币 +9 热心值 +3 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
zhczf + 1 + 1 用心讨论,共获提升!
helh0275 + 1 + 1 这个有时确实能用上,感谢制作分享

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

少马石 发表于 2025-4-7 15:26
不知道是啥原理,是在删除的地方填充0吗
RielCcc 发表于 2025-4-11 12:40
感觉还实现不了防恢复的效果,有个疑问是被占用的文件或者驱动能删吗,好像不行。不过感谢楼主分享思路。
kaixinguoguo 发表于 2025-4-7 14:58
mrliuyiming 发表于 2025-4-7 15:29
支持这个
xcgzs 发表于 2025-4-7 15:43
这个东西好啊
xiaoshuimian 发表于 2025-4-7 15:49
覆盖三次感觉不够
52PJ070 发表于 2025-4-7 16:06
试试看效果怎么样,感谢分享!
hexiwo 发表于 2025-4-7 16:10
大哥,给你提供个思路,修改原文件保存(等于破坏了原文件),然后删除,是否可以达到防恢复?
hollywu 发表于 2025-4-7 16:54
一般防删除,先改名,扩展名再删除再擦除比较好
ysjd22 发表于 2025-4-7 17:04
不错,不过电脑上装了火绒,就用火绒自带的了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-4-15 18:47

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表