修改Windows文件创建时间

修改Windows文件创建时间,附GUI界面与打包exe教程

📌 前言

在日常工作中,我们经常会遇到需要修改文件创建时间、修改时间、访问时间的场景。比如整理论文实验数据、归档旧文件、批量处理素材等。

Windows自带的属性面板只能查看,不能直接修改文件的创建时间。网上的工具要么收费,要么带广告,还担心有病毒。作为程序员,不如自己动手写一个!

本文将手把手教你用Python实现一个带图形界面的文件属性批量修改工具,支持:

  • ✅ 修改文件创建时间(最核心,也是最难实现的)
  • ✅ 修改文件修改时间
  • ✅ 修改文件访问时间
  • ✅ 修改文件名(单文件模式)
  • 单个文件模式
  • 文件夹批量模式(支持递归子文件夹)
  • ✅ 完美支持中文路径
  • ✅ 打包成独立exe,免安装直接运行

文末附完整源码和打包好的exe下载,建议收藏备用!


🎯 功能展示

核心特性

  1. 双模式切换:单个文件 / 文件夹批量,一键切换
  2. 独立控制:四项属性(文件名、创建时间、修改时间、访问时间)可独立勾选,想改哪个改哪个
  3. 批量递归:文件夹模式下可选择是否递归处理子文件夹
  4. 实时日志:执行过程实时显示,成功失败一目了然
  5. 输入校验:自动校验时间格式,避免非法输入
  6. 中文支持:完美支持中文文件名和中文路径

🔧 技术原理

为什么修改创建时间这么难?

很多人不知道,Python标准库的 os.utime() 只能修改访问时间和修改时间无法修改创建时间

这是因为:

  • Unix/Linux系统的文件系统原生只支持修改atime(访问时间)和mtime(修改时间)
  • Windows虽然有创建时间(ctime)的概念,但Python标准库没有提供跨平台的修改接口
  • 必须通过调用Windows原生API才能修改文件创建时间

实现方案对比

方案 优点 缺点
pywin32的SetFileTime 接口简单 依赖win32timezone模块,容易出问题
ctypes调用原生API 不依赖额外模块,稳定可靠 需要手动处理数据结构

本文采用 ctypes + Windows原生API 的方案,彻底解决win32timezone模块缺失的坑,打包成exe也不会出问题。

核心技术点

  1. Windows FILETIME结构体:Windows文件时间是以100纳秒为单位,从1601年1月1日开始计数的64位整数
  2. SetFileTime API:kernel32.dll中的原生函数,可同时设置创建、访问、修改三个时间
  3. CreateFile获取文件句柄:需要先打开文件获取句柄才能修改属性
  4. 时区转换:本地时间转UTC时间,避免时区偏差

💻 完整代码

1. 环境准备

需要安装pywin32库(用于获取文件句柄):

bash 复制代码
pip install pywin32

注:时间设置部分我们用ctypes原生实现,不依赖win32timezone,避免各种奇怪的报错。

2. 完整源码

python 复制代码
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import os
import win32file
import win32con
import ctypes
from ctypes import wintypes
from datetime import datetime, timezone


# 定义Windows原生FILETIME结构体
class FILETIME(ctypes.Structure):
    _fields_ = [
        ("dwLowDateTime", wintypes.DWORD),
        ("dwHighDateTime", wintypes.DWORD)
    ]


def datetime_to_filetime(dt):
    """将本地datetime转换为Windows原生FILETIME结构体,完全不依赖win32timezone"""
    # 转换为UTC时间
    dt_utc = dt.astimezone(timezone.utc)
    # Windows FILETIME基准:1601-01-01 00:00:00 UTC,与Unix纪元相差11644473600秒
    epoch_offset = 11644473600
    # 转换为100纳秒为单位的整数
    total_100ns = int((dt_utc.timestamp() + epoch_offset) * 10_000_000)
    # 拆分为高低32位
    low = total_100ns & 0xFFFFFFFF
    high = (total_100ns >> 32) & 0xFFFFFFFF
    return FILETIME(low, high)


def modify_file_info(file_path, rename=False, new_name="",
                     modify_ctime=False, ctime=None,
                     modify_mtime=False, mtime=None,
                     modify_atime=False, atime=None):
    """
    修改单个文件的属性:重命名、创建时间、修改时间、访问时间
    返回 (是否成功, 提示信息)
    """
    try:
        # 1. 处理时间修改(通过ctypes直接调用系统API,绕开win32timezone)
        if modify_ctime or modify_mtime or modify_atime:
            # 获取文件句柄
            file_handle = win32file.CreateFile(
                file_path,
                win32con.GENERIC_WRITE,
                win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE,
                None,
                win32con.OPEN_EXISTING,
                win32con.FILE_ATTRIBUTE_NORMAL,
                None
            )

            # 转换时间,未勾选项传None即不修改
            ctime_ft = ctypes.byref(datetime_to_filetime(ctime)) if modify_ctime else None
            atime_ft = ctypes.byref(datetime_to_filetime(atime)) if modify_atime else None
            mtime_ft = ctypes.byref(datetime_to_filetime(mtime)) if modify_mtime else None

            # 调用Windows原生SetFileTime API
            ctypes.windll.kernel32.SetFileTime(
                file_handle.handle,
                ctime_ft,
                atime_ft,
                mtime_ft
            )
            file_handle.Close()

        # 2. 处理文件重命名(仅单个文件模式启用)
        if rename and new_name.strip():
            dir_path = os.path.dirname(file_path)
            new_full_path = os.path.join(dir_path, new_name.strip())
            if os.path.exists(new_full_path):
                return False, "目标文件名已存在,无法覆盖"
            os.rename(file_path, new_full_path)

        return True, "修改成功"

    except PermissionError:
        return False, "权限不足,请以管理员身份运行"
    except Exception as e:
        return False, f"异常:{str(e)}"


def batch_modify_folder(folder_path, recursive=False, **kwargs):
    """
    批量修改文件夹下所有文件的属性
    返回结果列表 [(文件路径, 是否成功, 提示信息)]
    """
    results = []
    if recursive:
        # 递归遍历所有子目录
        for root, _, files in os.walk(folder_path):
            for filename in files:
                full_path = os.path.join(root, filename)
                success, msg = modify_file_info(full_path, **kwargs)
                results.append((full_path, success, msg))
    else:
        # 仅处理当前目录文件
        for item in os.listdir(folder_path):
            full_path = os.path.join(folder_path, item)
            if os.path.isfile(full_path):
                success, msg = modify_file_info(full_path, **kwargs)
                results.append((full_path, success, msg))
    return results


class FileAttributeTool(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("文件属性批量修改工具")
        self.geometry("760x580")
        self.resizable(False, False)

        # ========== 全局变量 ==========
        # 模式与路径
        self.mode_var = tk.StringVar(value="file")  # file=单个文件 folder=文件夹批量
        self.path_var = tk.StringVar()
        self.recursive_var = tk.BooleanVar(value=False)

        # 文件名设置
        self.rename_enable = tk.BooleanVar(value=False)
        self.new_name_var = tk.StringVar()

        # 创建时间
        self.ctime_enable = tk.BooleanVar(value=False)
        self.ctime_y = tk.StringVar(value="2025")
        self.ctime_m = tk.StringVar(value="01")
        self.ctime_d = tk.StringVar(value="01")
        self.ctime_h = tk.StringVar(value="00")
        self.ctime_min = tk.StringVar(value="00")
        self.ctime_s = tk.StringVar(value="00")

        # 修改时间
        self.mtime_enable = tk.BooleanVar(value=False)
        self.mtime_y = tk.StringVar(value="2025")
        self.mtime_m = tk.StringVar(value="01")
        self.mtime_d = tk.StringVar(value="01")
        self.mtime_h = tk.StringVar(value="00")
        self.mtime_min = tk.StringVar(value="00")
        self.mtime_s = tk.StringVar(value="00")

        # 访问时间
        self.atime_enable = tk.BooleanVar(value=False)
        self.atime_y = tk.StringVar(value="2025")
        self.atime_m = tk.StringVar(value="01")
        self.atime_d = tk.StringVar(value="01")
        self.atime_h = tk.StringVar(value="00")
        self.atime_min = tk.StringVar(value="00")
        self.atime_s = tk.StringVar(value="00")

        # 构建界面
        self.build_ui()
        self.refresh_widget_state()

    def build_ui(self):
        """构建所有界面元素"""
        time_labels = ["年", "月", "日", "时", "分", "秒"]

        # 1. 目标选择区域
        frame_path = ttk.LabelFrame(self, text="目标选择")
        frame_path.pack(fill="x", padx=12, pady=8)

        ttk.Radiobutton(
            frame_path, text="单个文件模式",
            variable=self.mode_var, value="file",
            command=self.refresh_widget_state
        ).grid(row=0, column=0, padx=8, pady=6)
        ttk.Radiobutton(
            frame_path, text="文件夹批量模式",
            variable=self.mode_var, value="folder",
            command=self.refresh_widget_state
        ).grid(row=0, column=1, padx=8, pady=6)

        ttk.Entry(frame_path, textvariable=self.path_var, width=75).grid(
            row=1, column=0, columnspan=3, padx=8, pady=6, sticky="w"
        )
        ttk.Button(frame_path, text="浏览", command=self.browse_target).grid(
            row=1, column=3, padx=8, pady=6
        )

        ttk.Checkbutton(
            frame_path, text="包含子文件夹(递归处理)",
            variable=self.recursive_var
        ).grid(row=2, column=0, columnspan=2, padx=8, pady=2, sticky="w")

        # 2. 文件名设置
        frame_name = ttk.LabelFrame(self, text="文件名设置")
        frame_name.pack(fill="x", padx=12, pady=5)

        self.ck_rename = ttk.Checkbutton(
            frame_name, text="修改文件名",
            variable=self.rename_enable, command=self.refresh_widget_state
        )
        self.ck_rename.grid(row=0, column=0, padx=8, pady=6, sticky="w")

        self.entry_name = ttk.Entry(
            frame_name, textvariable=self.new_name_var, width=40, state="disabled"
        )
        self.entry_name.grid(row=0, column=1, padx=8, pady=6, sticky="w")
        ttk.Label(
            frame_name, text="(仅单个文件可用,需包含扩展名,例如 文档.txt)"
        ).grid(row=0, column=2, padx=8, pady=6, sticky="w")

        # 3. 创建时间设置
        frame_ctime = ttk.LabelFrame(self, text="创建时间设置")
        frame_ctime.pack(fill="x", padx=12, pady=5)

        ttk.Checkbutton(
            frame_ctime, text="修改创建时间",
            variable=self.ctime_enable, command=self.refresh_widget_state
        ).grid(row=0, column=0, padx=8, pady=6, sticky="w")

        self.ctime_entry_list = []
        ctime_vars = [
            self.ctime_y, self.ctime_m, self.ctime_d,
            self.ctime_h, self.ctime_min, self.ctime_s
        ]
        for idx, (var, lab) in enumerate(zip(ctime_vars, time_labels)):
            entry = ttk.Entry(frame_ctime, textvariable=var, width=5, state="disabled")
            entry.grid(row=0, column=1 + idx * 2, padx=2, pady=6)
            ttk.Label(frame_ctime, text=lab).grid(
                row=0, column=2 + idx * 2, padx=1, pady=6, sticky="w"
            )
            self.ctime_entry_list.append(entry)

        # 4. 修改时间设置
        frame_mtime = ttk.LabelFrame(self, text="修改时间设置")
        frame_mtime.pack(fill="x", padx=12, pady=5)

        ttk.Checkbutton(
            frame_mtime, text="修改修改时间",
            variable=self.mtime_enable, command=self.refresh_widget_state
        ).grid(row=0, column=0, padx=8, pady=6, sticky="w")

        self.mtime_entry_list = []
        mtime_vars = [
            self.mtime_y, self.mtime_m, self.mtime_d,
            self.mtime_h, self.mtime_min, self.mtime_s
        ]
        for idx, (var, lab) in enumerate(zip(mtime_vars, time_labels)):
            entry = ttk.Entry(frame_mtime, textvariable=var, width=5, state="disabled")
            entry.grid(row=0, column=1 + idx * 2, padx=2, pady=6)
            ttk.Label(frame_mtime, text=lab).grid(
                row=0, column=2 + idx * 2, padx=1, pady=6, sticky="w"
            )
            self.mtime_entry_list.append(entry)

        # 5. 访问时间设置
        frame_atime = ttk.LabelFrame(self, text="访问时间设置")
        frame_atime.pack(fill="x", padx=12, pady=5)

        ttk.Checkbutton(
            frame_atime, text="修改访问时间",
            variable=self.atime_enable, command=self.refresh_widget_state
        ).grid(row=0, column=0, padx=8, pady=6, sticky="w")

        self.atime_entry_list = []
        atime_vars = [
            self.atime_y, self.atime_m, self.atime_d,
            self.atime_h, self.atime_min, self.atime_s
        ]
        for idx, (var, lab) in enumerate(zip(atime_vars, time_labels)):
            entry = ttk.Entry(frame_atime, textvariable=var, width=5, state="disabled")
            entry.grid(row=0, column=1 + idx * 2, padx=2, pady=6)
            ttk.Label(frame_atime, text=lab).grid(
                row=0, column=2 + idx * 2, padx=1, pady=6, sticky="w"
            )
            self.atime_entry_list.append(entry)

        # 6. 执行按钮
        ttk.Button(
            self, text="开始执行修改", command=self.run_task, width=22
        ).pack(pady=12)

        # 7. 日志输出区
        frame_log = ttk.LabelFrame(self, text="执行日志")
        frame_log.pack(fill="both", expand=True, padx=12, pady=5)

        self.log_box = tk.Text(frame_log, height=13, wrap="word")
        self.log_box.pack(fill="both", expand=True, padx=6, pady=6, side="left")
        scrollbar = ttk.Scrollbar(frame_log, command=self.log_box.yview)
        scrollbar.pack(side="right", fill="y")
        self.log_box.config(yscrollcommand=scrollbar.set)

    def refresh_widget_state(self):
        """根据勾选状态动态更新控件可用/禁用"""
        # 文件名:仅单个文件模式可用
        if self.mode_var.get() == "file":
            self.ck_rename.config(state="normal")
            state = "normal" if self.rename_enable.get() else "disabled"
            self.entry_name.config(state=state)
        else:
            self.ck_rename.config(state="disabled")
            self.entry_name.config(state="disabled")
            self.rename_enable.set(False)

        # 时间输入框状态
        state = "normal" if self.ctime_enable.get() else "disabled"
        for entry in self.ctime_entry_list:
            entry.config(state=state)

        state = "normal" if self.mtime_enable.get() else "disabled"
        for entry in self.mtime_entry_list:
            entry.config(state=state)

        state = "normal" if self.atime_enable.get() else "disabled"
        for entry in self.atime_entry_list:
            entry.config(state=state)

    def browse_target(self):
        """浏览选择文件或文件夹"""
        if self.mode_var.get() == "file":
            path = filedialog.askopenfilename(
                title="选择目标文件", filetypes=[("所有文件", "*.*")]
            )
        else:
            path = filedialog.askdirectory(title="选择目标文件夹")

        if path:
            self.path_var.set(path)

    def parse_datetime(self, y, m, d, h, minute, s):
        """解析时间字符串,合法返回datetime,失败返回None"""
        try:
            return datetime(int(y), int(m), int(d), int(h), int(minute), int(s))
        except ValueError:
            return None

    def append_log(self, text):
        """向日志框追加内容"""
        self.log_box.insert("end", text + "\n")
        self.log_box.see("end")
        self.update()

    def run_task(self):
        """执行修改主逻辑"""
        target_path = self.path_var.get().strip()
        if not target_path:
            messagebox.showwarning("提示", "请先选择目标文件或文件夹")
            return
        if not os.path.exists(target_path):
            messagebox.showerror("错误", "路径不存在,请检查路径是否正确")
            return

        # 校验至少勾选一项修改
        if not any([
            self.rename_enable.get(),
            self.ctime_enable.get(),
            self.mtime_enable.get(),
            self.atime_enable.get()
        ]):
            messagebox.showwarning("提示", "请至少勾选一项需要修改的内容")
            return

        # 校验所有时间格式
        ctime = mtime = atime = None
        if self.ctime_enable.get():
            ctime = self.parse_datetime(
                self.ctime_y.get(), self.ctime_m.get(), self.ctime_d.get(),
                self.ctime_h.get(), self.ctime_min.get(), self.ctime_s.get()
            )
            if not ctime:
                messagebox.showerror("错误", "创建时间格式不合法,请检查日期")
                return

        if self.mtime_enable.get():
            mtime = self.parse_datetime(
                self.mtime_y.get(), self.mtime_m.get(), self.mtime_d.get(),
                self.mtime_h.get(), self.mtime_min.get(), self.mtime_s.get()
            )
            if not mtime:
                messagebox.showerror("错误", "修改时间格式不合法,请检查日期")
                return

        if self.atime_enable.get():
            atime = self.parse_datetime(
                self.atime_y.get(), self.atime_m.get(), self.atime_d.get(),
                self.atime_h.get(), self.atime_min.get(), self.atime_s.get()
            )
            if not atime:
                messagebox.showerror("错误", "访问时间格式不合法,请检查日期")
                return

        # 清空日志
        self.log_box.delete("1.0", "end")
        self.append_log("========== 任务开始执行 ==========")

        # 组装参数
        params = {
            "rename": self.rename_enable.get(),
            "new_name": self.new_name_var.get(),
            "modify_ctime": self.ctime_enable.get(),
            "ctime": ctime,
            "modify_mtime": self.mtime_enable.get(),
            "mtime": mtime,
            "modify_atime": self.atime_enable.get(),
            "atime": atime,
        }

        # 执行对应模式
        if self.mode_var.get() == "file":
            if not os.path.isfile(target_path):
                messagebox.showerror("错误", "当前路径不是文件,请切换为文件夹模式")
                return
            success, msg = modify_file_info(target_path, **params)
            status = "✅ 成功" if success else "❌ 失败"
            self.append_log(f"{status} | {target_path}:{msg}")
            self.append_log("\n========== 任务执行完成 ==========")

        else:
            if not os.path.isdir(target_path):
                messagebox.showerror("错误", "当前路径不是文件夹,请切换为文件模式")
                return

            results = batch_modify_folder(
                target_path, recursive=self.recursive_var.get(), **params
            )
            success_count = 0
            fail_count = 0
            for file_path, success, msg in results:
                flag = "✅" if success else "❌"
                if success:
                    success_count += 1
                else:
                    fail_count += 1
                self.append_log(f"{flag} | {file_path}:{msg}")

            self.append_log(f"\n========== 任务执行完成 ==========")
            self.append_log(
                f"总计处理 {len(results)} 个文件,成功 {success_count} 个,失败 {fail_count} 个"
            )

        messagebox.showinfo("完成", "执行结束,详细结果请查看日志")


if __name__ == "__main__":
    # 解决Windows高DPI下界面模糊问题
    try:
        from ctypes import windll
        windll.shcore.SetProcessDpiAwareness(1)
    except Exception:
        pass

    app = FileAttributeTool()
    app.mainloop()

📖 使用教程

1. 单个文件修改

  1. 选择「单个文件模式」
  2. 点击「浏览」选择要修改的文件
  3. 勾选需要修改的项(文件名/创建时间/修改时间/访问时间)
  4. 输入对应的值
  5. 点击「开始执行修改」

2. 文件夹批量修改

  1. 选择「文件夹批量模式」
  2. 点击「浏览」选择目标文件夹
  3. 勾选「包含子文件夹」可递归处理所有子目录
  4. 勾选需要修改的时间项
  5. 点击「开始执行修改」

3. 注意事项

  • ⚠️ 修改前务必备份重要文件,避免误操作
  • ⚠️ 修改系统目录(如 C:\WindowsProgram Files)的文件时,需要右键以管理员身份运行
  • ✅ 支持所有文件类型,无格式限制
  • ✅ 完美支持中文路径和中文文件名

📦 打包成独立exe

1. 安装PyInstaller

bash 复制代码
pip install pyinstaller

2. 添加版本信息(可选,让exe更专业)

新建 version_info.txt 文件,填入以下内容(可自定义发行商、版权等信息):

python 复制代码
VSVersionInfo(
  ffi=FixedFileInfo(
    filevers=(1, 0, 0, 0),
    prodvers=(1, 0, 0, 0),
    mask=0x3f,
    flags=0x0,
    OS=0x40004,
    fileType=0x1,
    subtype=0x0,
    date=(0, 0)
  ),
  kids=[
    StringFileInfo(
      [
      StringTable(
        u'080404B0',
        [
        StringStruct(u'CompanyName', u'你的名称'),
        StringStruct(u'FileDescription', u'文件属性批量修改工具'),
        StringStruct(u'FileVersion', u'1.0.0.0'),
        StringStruct(u'InternalName', u'FileAttrTool'),
        StringStruct(u'LegalCopyright', u'© 2025 你的名称. 保留所有权利.'),
        StringStruct(u'OriginalFilename', u'文件属性修改工具.exe'),
        StringStruct(u'ProductName', u'文件属性批量修改工具')
        ])
      ]),
    VarFileInfo([VarStruct(u'Translation', [2052, 1200])])
  ]
)

3. 执行打包命令

bash 复制代码
pyinstaller -F -w --version-file version_info.txt --name "文件属性修改工具" file_attr_tool.py

参数说明:

  • -F:打包为单个独立exe文件
  • -w:不显示控制台窗口,纯GUI界面
  • --version-file:嵌入版本信息
  • --name:自定义exe文件名

打包完成后,在 dist 文件夹中就能找到生成的exe文件,双击即可运行,无需安装Python环境!


4.加密打包

报错核心原因

你使用的 PyArmor 9.2.5 版本 中,pyarmor build 是用于构建加密工程的命令,不负责调用 PyInstaller 打包 EXE,也不支持 -- 分隔符传参,因此所有打包参数都会被识别为无效参数。

PyArmor 9.x 的「代码混淆 + 打包 EXE」一体化功能,是通过 pyarmor gen 命令的 --pack 参数实现的;额外的 PyInstaller 参数需要先通过配置项设置,不能直接拼接在命令末尾。


正确操作方案

方案一:一体化加密打包(推荐,自动处理依赖)

分两步执行:先配置 PyInstaller 参数,再执行打包。

  1. 设置打包参数到配置项

    bash 复制代码
    pyarmor cfg pack:pyi_options = " --windowed --name \"文件属性修改工具\" --version-file version_info.txt"

    注意:引号开头必须有一个空格;中文名称的双引号需要转义包裹。

  2. 执行一体化加密+打包

    bash 复制代码
    pyarmor gen --pack onefile file_attr_tool.py

执行完成后,最终的单文件 EXE 会生成在 dist 目录中。

如果后续不需要保留该打包配置,可执行命令清除:

bash 复制代码
pyarmor cfg -d pack:pyi_options
方案二:两步手动打包(更灵活可控)

你已经成功用 pyarmor gen 完成了代码加密,可直接用 PyInstaller 打包加密后的脚本,无需调整 pyarmor 配置:

bash 复制代码
pyinstaller --onefile --windowed --name "文件属性修改工具" --version-file version_info.txt dist/file_attr_tool.py

补充说明

  • 请确保 version_info.txt 在当前执行命令的目录下,若文件在其他位置,请填写完整的绝对路径。
  • 若打包后运行提示缺少运行时依赖,优先使用方案一的一体化打包,PyArmor 会自动处理运行时文件的嵌入。

需要我帮你排查打包后运行闪退、体积过大这类常见问题吗?

🐛 踩坑记录

坑1:No module named 'win32timezone'

问题:使用pywin32的SetFileTime时,传入datetime对象会报这个错。

原因:pywin32安装后没有执行后置注册脚本,或者PyInstaller打包时漏了这个模块。

解决方案:用ctypes直接调用Windows原生API,彻底绕开对win32timezone的依赖(本文采用的方案)。

坑2:must be a pywintypes time object (got int)

问题:自己转成整数传给SetFileTime会报类型错误。

原因:win32file.SetFileTime只接受pywintypes的时间对象,不接受原始整数。

解决方案:用ctypes.windll.kernel32.SetFileTime,传入FILETIME结构体指针即可。

坑3:PowerShell中conda activate报错

问题CondaError: Run 'conda init' before 'conda activate'

原因:PowerShell默认没有加载conda配置。

解决方案 :执行 conda init powershell 后重启终端,或者直接用Anaconda Prompt。


🎁 资源下载

我已经把工具打包好了,不想自己搭环境的朋友可以直接下载使用:

  • 👉 文件属性修改工具.exe(见本文附件资源)
  • 绿色免安装,双击直接运行
  • 支持Windows 7/10/11

📝 总结

这个工具虽然功能简单,但实用性很强,特别是批量处理实验数据、整理文件归档的时候特别好用。

核心技术点总结:

  1. Python标准库无法修改文件创建时间,必须调用Windows API
  2. 使用ctypes可以绕过pywin32的各种依赖问题
  3. FILETIME是100纳秒为单位的64位整数,基准是1601年1月1日
  4. 注意时区转换,避免时间偏差

如果觉得有用,欢迎点赞、收藏、关注!有问题可以在评论区留言交流~


版权声明:本文为原创文章,转载请注明出处。工具仅供个人学习使用,请勿用于非法用途。