吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5145|回复: 28
收起左侧

[Python 原创] 批量删除文件属性的信息

  [复制链接]
xuguoguo 发表于 2025-2-28 18:30
本帖最后由 xuguoguo 于 2025-3-5 18:48 编辑

电脑抽风了,文件全选不能删除属性和个人信息,搜了下论坛好像也找不到相关的文件,着急就搞了个软件,功能很简单,批量选择文件,批量删除属性信息,具体信息大家看吧,东西很小,也不打包了,直接运行就行{:301_1000:}
文件信息删除点不了{:1_908:}

属性界面

属性界面

运行界面

1740738711953.jpg

2025.3.5  应大家要求,稍微改了一下,补一下exe链接。
链接: https://pan.baidu.com/s/18MR-FAgNQL0-hZocn2im_w?pwd=52pj 提取码: 52pj

[Python] 纯文本查看 复制代码
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import os
import tempfile
import shutil
import zipfile
from datetime import datetime
from lxml import etree
from openpyxl import load_workbook
from PyPDF2 import PdfReader, PdfWriter


class FileMetadataCleaner:
    def __init__(self, master):
        self.master = master
        master.title("文件元数据清理工具 v4.0")
        master.geometry("800x600")

        # 初始化变量
        self.selected_files = []
        self.output_dir = ""
        self.error_log = []

        # 创建界面组件
        self.create_widgets()

    def create_widgets(self):
        # 主容器
        main_frame = tk.Frame(self.master, padx=20, pady=20)
        main_frame.pack(fill=tk.BOTH, expand=True)

        # 文件选择区域
        file_frame = tk.LabelFrame(main_frame, text="文件操作")
        file_frame.pack(fill=tk.X, pady=5)

        self.btn_select = tk.Button(
            file_frame,
            text="选择文件",
            command=self.select_files,
            width=15
        )
        self.btn_select.pack(side=tk.LEFT, padx=5)

        self.btn_dir = tk.Button(
            file_frame,
            text="选择保存目录",
            command=self.select_directory,
            width=15
        )
        self.btn_dir.pack(side=tk.LEFT, padx=5)

        self.btn_convert = tk.Button(
            file_frame,
            text="开始清理",
            command=self.start_cleaning,
            state=tk.DISABLED,
            width=15
        )
        self.btn_convert.pack(side=tk.LEFT, padx=5)

        # 文件列表
        list_frame = tk.LabelFrame(main_frame, text="待处理文件")
        list_frame.pack(fill=tk.BOTH, expand=True, pady=5)

        self.listbox = tk.Listbox(
            list_frame,
            width=100,
            height=15,
            selectmode=tk.EXTENDED
        )
        self.listbox.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        # 进度条
        self.progress = ttk.Progressbar(
            main_frame,
            orient=tk.HORIZONTAL,
            mode='determinate'
        )
        self.progress.pack(fill=tk.X, pady=5)

        # 状态栏
        self.status = tk.Label(
            main_frame,
            text="就绪",
            bd=1,
            relief=tk.SUNKEN,
            anchor=tk.W
        )
        self.status.pack(fill=tk.X)

    def select_files(self):
        filetypes = [
            ("所有文档", "*.doc;*.docx;*.xls;*.xlsx;*.pdf"),
            ("Word 文档", "*.doc;*.docx"),
            ("Excel 文档", "*.xls;*.xlsx"),
            ("PDF 文档", "*.pdf")
        ]
        files = filedialog.askopenfilenames(filetypes=filetypes)
        if files:
            self.selected_files = list(files)
            self.listbox.delete(0, tk.END)
            for f in self.selected_files:
                self.listbox.insert(tk.END, f)
            self.check_ready_state()
            self.update_status(f"已选择 {len(files)} 个文件")

    def select_directory(self):
        self.output_dir = filedialog.askdirectory()
        if self.output_dir:
            self.check_ready_state()
            self.update_status(f"保存目录:{self.output_dir}")

    def check_ready_state(self):
        if self.selected_files and self.output_dir:
            self.btn_convert.config(state=tk.NORMAL)
        else:
            self.btn_convert.config(state=tk.DISABLED)

    def start_cleaning(self):
        if not self.selected_files or not self.output_dir:
            return

        total_files = len(self.selected_files)
        success_count = 0
        self.error_log = []

        try:
            for index, file_path in enumerate(self.selected_files, 1):
                filename = os.path.basename(file_path)
                file_ext = os.path.splitext(file_path)[1].lower()

                self.update_status(f"正在处理 {filename} ({index}/{total_files})")
                self.progress['value'] = (index / total_files) * 100
                self.master.update_idletasks()

                try:
                    output_path = os.path.join(self.output_dir, filename)

                    if file_ext in ('.doc', '.docx'):
                        self.process_word(file_path, output_path)
                    elif file_ext in ('.xls', '.xlsx'):
                        self.process_excel(file_path, output_path)
                    elif file_ext == '.pdf':
                        self.process_pdf(file_path, output_path)
                    else:
                        raise ValueError("不支持的文件类型")

                    success_count += 1
                except Exception as e:
                    self.error_log.append((filename, str(e)))
                    continue

            result_msg = [
                f"处理完成!成功:{success_count}/{total_files}",
                f"失败:{len(self.error_log)} 个文件" if self.error_log else ""
            ]
            self.update_status(" ".join(result_msg))
            messagebox.showinfo("完成", "\n".join(result_msg))

            if self.error_log:
                self.save_error_log()

        except Exception as e:
            messagebox.showerror("系统错误", f"处理过程中断:{str(e)}")
        finally:
            self.progress['value'] = 0

    def process_word(self, input_path, output_path):
        """处理Word文档(增强版)"""
        try:
            if not self.is_valid_docx(input_path):
                raise ValueError("无效的Word文档格式")

            temp_dir = tempfile.mkdtemp()

            try:
                # 解压原始文档
                with zipfile.ZipFile(input_path) as zip_ref:
                    zip_ref.extractall(temp_dir)

                # 清理核心元数据
                core_xml_path = os.path.join(temp_dir, 'docProps', 'core.xml')
                if os.path.exists(core_xml_path):
                    self.clean_core_xml(core_xml_path)

                # 重新打包
                with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as new_zip:
                    for root, dirs, files in os.walk(temp_dir):
                        for file in files:
                            file_path = os.path.join(root, file)
                            arcname = os.path.relpath(file_path, temp_dir)
                            new_zip.write(file_path, arcname)

            finally:
                shutil.rmtree(temp_dir)

        except Exception as e:
            raise RuntimeError(f"Word处理失败: {str(e)}")

    def is_valid_docx(self, file_path):
        """验证docx文件有效性"""
        try:
            with zipfile.ZipFile(file_path) as z:
                return 'word/document.xml' in z.namelist()
        except:
            return False

    def clean_core_xml(self, xml_path):
        """清理核心元数据XML"""
        try:
            parser = etree.XMLParser(remove_blank_text=True)
            tree = etree.parse(xml_path, parser)
            root = tree.getroot()

            namespaces = {
                'cp': "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
                'dc': "http://purl.org/dc/elements/1.1/",
                'dcterms': "http://purl.org/dc/terms/"
            }

            # 清理文本字段
            elements_to_clear = [
                ('cp:lastModifiedBy', ''),
                ('dc:creator', ''),
                ('cp:revision', '1'),
                ('dc:title', ''),
                ('dc:subject', ''),
                ('cp:keywords', ''),
                ('dc:description', ''),
                ('cp:category', '')
            ]

            for xpath, value in elements_to_clear:
                for elem in root.xpath(xpath, namespaces=namespaces):
                    elem.text = value

            # 设置基准时间
            base_time = datetime(2000, 1, 1).isoformat()
            for elem in root.xpath('//dcterms:created | //dcterms:modified', namespaces=namespaces):
                elem.text = base_time

            tree.write(xml_path, encoding='UTF-8', xml_declaration=True)

        except Exception as e:
            raise RuntimeError(f"XML清理失败: {str(e)}")

    def process_excel(self, input_path, output_path):
        """处理Excel文档"""
        try:
            wb = load_workbook(input_path)
            props = wb.properties

            # 清除元数据
            props.creator = props.lastModifiedBy = ""
            props.title = props.subject = ""
            props.description = props.keywords = ""
            props.created = props.modified = datetime(2000, 1, 1)

            wb.save(output_path)
        except Exception as e:
            raise RuntimeError(f"Excel处理失败: {str(e)}")

    def process_pdf(self, input_path, output_path):
        """处理PDF文档"""
        try:
            reader = PdfReader(input_path)
            writer = PdfWriter()

            for page in reader.pages:
                writer.add_page(page)

            # 清除元数据
            metadata = {
                '/Author': '',
                '/Title': '',
                '/Subject': '',
                '/Keywords': '',
                '/CreationDate': datetime(2000, 1, 1).strftime('D:%Y%m%d%H%M%S'),
                '/ModDate': datetime(2000, 1, 1).strftime('D:%Y%m%d%H%M%S')
            }
            writer.add_metadata(metadata)

            with open(output_path, 'wb') as f:
                writer.write(f)
        except Exception as e:
            raise RuntimeError(f"PDF处理失败: {str(e)}")

    def save_error_log(self):
        """保存错误日志"""
        log_path = os.path.join(self.output_dir, "processing_errors.log")
        try:
            with open(log_path, 'w', encoding='utf-8') as f:
                f.write("文件处理错误日志\n")
                f.write(f"生成时间:{datetime.now()}\n\n")
                for filename, error in self.error_log:
                    f.write(f"文件:{filename}\n错误:{error}\n\n")
            messagebox.showinfo("错误日志", f"错误日志已保存到:\n{log_path}")
        except Exception as e:
            messagebox.showerror("日志错误", f"无法保存错误日志:{str(e)}")

    def update_status(self, message):
        self.status.config(text=message)
        self.master.update_idletasks()


if __name__ == "__main__":
    root = tk.Tk()
    app = FileMetadataCleaner(root)
    root.mainloop()


免费评分

参与人数 8吾爱币 +14 热心值 +6 收起 理由
hcx181920 + 1 + 1 大佬,麻烦补一个链接
ceo977 + 1 楼主,可以在分享一次么
叫我塞纳 + 1 + 1 链接不能下载了,楼主能不能再分享一下,谢谢。
voslune + 1 + 1 用心讨论,共获提升!
tzq001 + 1 + 1 用心讨论,共获提升!
HXlyf + 1 用心讨论,共获提升!
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
grrr_zhao + 1 + 1 谢谢@Thanks!

查看全部评分

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

W98 发表于 2025-2-28 21:33
文件源数据清理工具 V4.0.exe_20250228_213304.png 怎么打包?
zhangtian325 发表于 2025-2-28 20:55
lovlss 发表于 2025-2-28 21:00
 楼主| xuguoguo 发表于 2025-2-28 21:17

没有压制成exe,在pycharm中安装相应库以后可以直接运行
lovlss 发表于 2025-2-28 22:34

运行报错了?为啥??
qaz3713 发表于 2025-2-28 22:44
怎么才能修改岛津气相色谱文件采集时间属性的
adfsd 发表于 2025-2-28 23:40
看来多少需要一点学习成本,学习了
加奈绘 发表于 2025-3-1 00:05
学到了,同理而言还可以给文件加属性
52wjj 发表于 2025-3-1 00:31
感谢分享!正好我有很多音乐文件需要属性里的信息来整理
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2026-7-14 22:53

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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