-
选择文件夹并递归列出所有文件
-
在表格里看到每个文件的"计划创建时间 / 计划修改时间"
-
选中一个或多个文件后,单独设置时间(每个文件都可不同)
-
点击"执行写入"后真正修改
-
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()