小工具备份

  • 选择文件夹并递归列出所有文件

  • 在表格里看到每个文件的"计划创建时间 / 计划修改时间"

  • 选中一个或多个文件后,单独设置时间(每个文件都可不同)

  • 点击"执行写入"后真正修改

  • Windows 下支持"创建时间+修改时间",Linux/macOS 只改修改时间

python 复制代码
import os
import platform
import subprocess
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from datetime import datetime

TIME_FMT = "%Y-%m-%d %H:%M:%S"


def fmt_dt(ts: float) -> str:
    return datetime.fromtimestamp(ts).strftime(TIME_FMT)


def parse_dt(s: str, field_name="时间") -> datetime:
    try:
        return datetime.strptime(s.strip(), TIME_FMT)
    except ValueError:
        raise ValueError(f"{field_name}格式错误:请使用 YYYY-MM-DD HH:MM:SS")


def set_creation_time_windows(path: str, dt: datetime):
    """
    Windows: 通过 PowerShell 设置创建时间
    """
    dt_str = dt.strftime(TIME_FMT)
    safe_path = path.replace("'", "''")
    ps_cmd = (
        "$p = Get-Item -LiteralPath '{0}'; "
        "$p.CreationTime = [datetime]'{1}'"
    ).format(safe_path, dt_str)

    subprocess.run(
        ["powershell", "-NoProfile", "-Command", ps_cmd],
        check=True,
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL
    )


def set_modified_time(path: str, dt: datetime):
    ts = dt.timestamp()
    # atime, mtime
    os.utime(path, (ts, ts))


class TimeEditorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("按文件分别修改时间(可视化)")
        self.root.geometry("1200x700")

        self.files_data = {}  # iid -> {"path", "create_plan", "modify_plan"}

        self.build_ui()

    def build_ui(self):
        top = tk.Frame(self.root, padx=10, pady=10)
        top.pack(fill="x")

        self.path_var = tk.StringVar()
        tk.Label(top, text="目标文件夹:").pack(side="left")
        tk.Entry(top, textvariable=self.path_var, width=90).pack(side="left", padx=6)
        tk.Button(top, text="选择文件夹", command=self.choose_folder).pack(side="left", padx=4)
        tk.Button(top, text="加载文件", command=self.load_files).pack(side="left", padx=4)

        middle = tk.Frame(self.root, padx=10, pady=5)
        middle.pack(fill="both", expand=True)

        # 表格
        columns = ("path", "create_plan", "modify_plan")
        self.tree = ttk.Treeview(middle, columns=columns, show="headings", selectmode="extended")
        self.tree.heading("path", text="文件路径")
        self.tree.heading("create_plan", text="计划创建时间")
        self.tree.heading("modify_plan", text="计划修改时间")

        self.tree.column("path", width=740, anchor="w")
        self.tree.column("create_plan", width=200, anchor="center")
        self.tree.column("modify_plan", width=200, anchor="center")

        yscroll = ttk.Scrollbar(middle, orient="vertical", command=self.tree.yview)
        self.tree.configure(yscrollcommand=yscroll.set)
        self.tree.pack(side="left", fill="both", expand=True)
        yscroll.pack(side="right", fill="y")

        # 下方控制区
        bottom = tk.Frame(self.root, padx=10, pady=10)
        bottom.pack(fill="x")

        tk.Label(bottom, text="创建时间(YYYY-MM-DD HH:MM:SS):").grid(row=0, column=0, sticky="w")
        self.create_var = tk.StringVar()
        tk.Entry(bottom, textvariable=self.create_var, width=25).grid(row=0, column=1, sticky="w", padx=4)

        tk.Label(bottom, text="修改时间(YYYY-MM-DD HH:MM:SS):").grid(row=0, column=2, sticky="w", padx=(20, 0))
        self.modify_var = tk.StringVar()
        tk.Entry(bottom, textvariable=self.modify_var, width=25).grid(row=0, column=3, sticky="w", padx=4)

        tk.Button(bottom, text="读取当前时间到输入框", command=self.fill_inputs_from_selected).grid(row=0, column=4, padx=8)
        tk.Button(bottom, text="应用到选中文件", command=self.apply_to_selected).grid(row=0, column=5, padx=4)
        tk.Button(bottom, text="应用到全部文件", command=self.apply_to_all).grid(row=0, column=6, padx=4)

        tk.Button(bottom, text="执行写入(真正修改)", command=self.commit_changes, bg="#2d7", width=18).grid(
            row=1, column=6, pady=(10, 0), sticky="e"
        )

        tip = (
            "说明:\n"
            "1) 先加载文件,再选中行,输入时间,点"应用到选中"。\n"
            "2) 每个文件可设置不同时间(分批选中操作即可)。\n"
            "3) Windows支持创建时间+修改时间;Linux/macOS通常只支持修改时间。"
        )
        tk.Label(bottom, text=tip, fg="gray", justify="left").grid(row=1, column=0, columnspan=6, sticky="w", pady=(10, 0))

    def choose_folder(self):
        folder = filedialog.askdirectory(title="选择文件夹")
        if folder:
            self.path_var.set(folder)

    def load_files(self):
        folder = self.path_var.get().strip()
        if not folder or not os.path.isdir(folder):
            messagebox.showerror("错误", "请先选择有效文件夹")
            return

        self.tree.delete(*self.tree.get_children())
        self.files_data.clear()

        count = 0
        for root, _, files in os.walk(folder):
            for f in files:
                p = os.path.join(root, f)
                try:
                    st = os.stat(p)
                    c = fmt_dt(st.st_ctime)
                    m = fmt_dt(st.st_mtime)
                except Exception:
                    c, m = "", ""

                iid = self.tree.insert("", "end", values=(p, c, m))
                self.files_data[iid] = {
                    "path": p,
                    "create_plan": c,
                    "modify_plan": m
                }
                count += 1

        messagebox.showinfo("完成", f"已加载 {count} 个文件")

    def fill_inputs_from_selected(self):
        selected = self.tree.selection()
        if not selected:
            messagebox.showwarning("提示", "请先选中文件")
            return
        iid = selected[0]
        data = self.files_data[iid]
        self.create_var.set(data["create_plan"])
        self.modify_var.set(data["modify_plan"])

    def apply_to_selected(self):
        selected = self.tree.selection()
        if not selected:
            messagebox.showwarning("提示", "请先选中文件")
            return

        create_text = self.create_var.get().strip()
        modify_text = self.modify_var.get().strip()

        # 允许只填其中一个
        create_dt = None
        modify_dt = None
        try:
            if create_text:
                create_dt = parse_dt(create_text, "创建时间")
            if modify_text:
                modify_dt = parse_dt(modify_text, "修改时间")
        except ValueError as e:
            messagebox.showerror("输入错误", str(e))
            return

        if not create_dt and not modify_dt:
            messagebox.showwarning("提示", "请至少填写创建时间或修改时间")
            return

        for iid in selected:
            data = self.files_data[iid]
            if create_dt:
                data["create_plan"] = create_dt.strftime(TIME_FMT)
            if modify_dt:
                data["modify_plan"] = modify_dt.strftime(TIME_FMT)

            self.tree.item(iid, values=(data["path"], data["create_plan"], data["modify_plan"]))

        messagebox.showinfo("完成", f"已更新 {len(selected)} 个选中文件的计划时间")

    def apply_to_all(self):
        all_iids = self.tree.get_children()
        if not all_iids:
            messagebox.showwarning("提示", "请先加载文件")
            return

        create_text = self.create_var.get().strip()
        modify_text = self.modify_var.get().strip()

        create_dt = None
        modify_dt = None
        try:
            if create_text:
                create_dt = parse_dt(create_text, "创建时间")
            if modify_text:
                modify_dt = parse_dt(modify_text, "修改时间")
        except ValueError as e:
            messagebox.showerror("输入错误", str(e))
            return

        if not create_dt and not modify_dt:
            messagebox.showwarning("提示", "请至少填写创建时间或修改时间")
            return

        for iid in all_iids:
            data = self.files_data[iid]
            if create_dt:
                data["create_plan"] = create_dt.strftime(TIME_FMT)
            if modify_dt:
                data["modify_plan"] = modify_dt.strftime(TIME_FMT)
            self.tree.item(iid, values=(data["path"], data["create_plan"], data["modify_plan"]))

        messagebox.showinfo("完成", f"已更新全部 {len(all_iids)} 个文件的计划时间")

    def commit_changes(self):
        all_iids = self.tree.get_children()
        if not all_iids:
            messagebox.showwarning("提示", "没有可写入的文件")
            return

        ok = messagebox.askyesno("确认", "将按表格中的"计划时间"写入到每个文件,是否继续?")
        if not ok:
            return

        system = platform.system()
        success = 0
        failed = 0
        fail_msgs = []

        for iid in all_iids:
            data = self.files_data[iid]
            path = data["path"]
            try:
                # 修改时间(跨平台)
                if data["modify_plan"]:
                    mdt = parse_dt(data["modify_plan"], "修改时间")
                    set_modified_time(path, mdt)

                # 创建时间(Windows)
                if data["create_plan"] and system == "Windows":
                    cdt = parse_dt(data["create_plan"], "创建时间")
                    set_creation_time_windows(path, cdt)

                success += 1
            except Exception as e:
                failed += 1
                fail_msgs.append(f"{path}\n  -> {e}")

        msg = f"写入完成。\n成功: {success}\n失败: {failed}"
        if system != "Windows":
            msg += "\n\n当前系统通常不支持修改创建时间,已自动跳过创建时间写入。"

        if failed > 0:
            messagebox.showwarning("部分失败", msg + "\n\n前5条失败示例:\n" + "\n\n".join(fail_msgs[:5]))
        else:
            messagebox.showinfo("完成", msg)


def main():
    root = tk.Tk()
    app = TimeEditorApp(root)
    root.mainloop()


if __name__ == "__main__":
    main()
相关推荐
阿_旭2 小时前
基于YOLO26深度学习的【咖啡果实成熟度检测与计数系统】【python源码+Pyqt5界面+数据集+训练代码】
人工智能·python·深度学习·咖啡果实检测
灰色人生qwer2 小时前
python 中 BaseModel 在这里有什么用?
开发语言·python·状态模式
AI技术控2 小时前
ReAct 论文解读:大模型 Agent 如何通过“推理 + 行动”完成复杂任务
人工智能·python·语言模型·自然语言处理·nlp
wang3zc2 小时前
如何设置密码复杂度策略以约束MongoDB用户的密码强度
jvm·数据库·python
紫洋葱hh2 小时前
LangChain 结构化输出详解:彻底告别大模型文本手动解析
人工智能·python·ai·langchain·llm·agent·大模型应用开发
weelinking6 小时前
【2026】08_Claude与版本控制:Git协作技巧
数据库·人工智能·git·python·数据挖掘·交互·cloudera
scan72411 小时前
智能体多个工具调用
python
2401_8676239811 小时前
CSS Flex布局中如何设置子元素间距_掌握gap属性的现代用法
jvm·数据库·python
即使再小的船也能远航11 小时前
【Python】安装
开发语言·python