小工具备份

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

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

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

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

  • 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()
相关推荐
青 春 记 忆4 小时前
Dify Docker Compose 通用无损升级指南:从备份、双版本预演到切换与回滚
运维·人工智能·python·docker·容器
GlueNa2SiO34 小时前
03-Flask模板引擎Jinja2详解
笔记·python·flask
临沂GEO7 小时前
GEO搜索优化科普|正规地理位置流量运营入门指南
大数据·人工智能·python·流量运营
大模型码小白7 小时前
Spring AI Tool 实现自然语言操作 MySQL 数据库详解
服务器·开发语言·数据库·人工智能·python·mysql·spring
荷蒲8 小时前
【小白量化Qbuddy】利用AI学习中文Python
人工智能·python·学习
数据狐(Datafox)10 小时前
京东商品列表API技术解析与落地应用(含标准 JSON 示例)
java·大数据·前端·人工智能·python·数据分析·json
量化吞吐机10 小时前
2026年下半年手工交易规则走向量化表达,产品该先接住哪一步
人工智能·python
Metaphor69210 小时前
使用 Python 读取和删除 Excel 文件属性
python·excel
迷迭香yy11 小时前
Python构建转融券多空识别系统从接口到因子的全流程 IG50免费开源股票数据API接口
开发语言·python·开源
月光船幽幽12 小时前
真实即粗糙,光滑是伪造
人工智能·python