Python在Windows关机时如何保存集合到文件?
我不想在Windows要关机、重启、注销或睡眠的时候丢失我的设置。有没有办法在关机之前保存这些设置?或者有没有其他方法可以保存信息,让我不用担心在Windows关机时会丢失?比如说用JSON、CSV、数据库之类的?有什么建议吗?
s = {1,2,3,4}
with open("s.pick","wb") as f: # pickle it to file when PC about to shutdown to save information
pickle.dump(s,f)
2 个回答
你可以通过 win32api.setConsoleCtrlHandler
来检测 Windows 的关机或注销操作。
这里有一个不错的例子,讲解了如何用 Python 捕捉这些“杀死”事件,链接在这里:如何捕捉“杀死”事件
我不想在Windows关机、重启、注销或睡眠时丢失我的设置,能在关机前保存它们吗?
可以的,如果你写了一个有消息循环的应用程序,你可以接收到一个叫做 WM_QUERYENDSESSION
的消息。如果你想要一个图形界面(GUI),大多数图形库可能会以自己的方式处理这个消息。如果你不需要图形界面,最简单的办法可能是使用 PyWin32。在文档中有一个关于创建隐藏窗口和写简单消息循环的教程。只需在主线程中执行这个,然后在后台线程中进行实际工作,当收到 WM_QUERYENDSESSION
消息时,通知你的后台线程。
或者,更简单的是,正如Evgeny Prokurat所建议的,直接使用 SetConsoleCtrlHandler
(同样通过PyWin32)。这个方法可以捕捉到 ^C、^BREAK 和用户关闭控制台的情况,以及 WM_QUERYENDSESSION
捕捉到的注销和关机消息。更重要的是,它不需要消息循环,所以如果你没有其他需要消息循环的地方,这样做简单得多。
有没有其他方法可以保存信息,而不必担心在Windows关机时会丢失?比如JSON、CSV、数据库?有什么建议吗?
文件格式并不会神奇地解决问题。不过,使用数据库可能有两个好处。
首先,你可以通过尽可能频繁地写入来减少问题。但对于大多数文件格式来说,这意味着需要尽可能频繁地重写整个文件,这会非常慢。解决方案是将数据流式写入一个更简单的“日志”文件,较少地将其打包到真实文件中,并在每次启动时检查是否有剩余的日志。你可以手动做到这一点,但数据库通常会自动为你处理。
其次,如果在写入过程中程序被杀掉,你可能会得到一个半成品的文件。你可以通过原子写入的技巧来解决这个问题——先写一个临时文件,然后用临时文件替换旧文件,但在Windows上做到这一点比较困难(尤其是使用Python 2.x)(参见 如何正确进行原子写入),而数据库通常会为你处理这个问题。
正确的做法是创建一个新的窗口类,并在 WM_QUERYENDSESSION
消息到达时调用你的处理程序。就像MFC让这比原始的Win32 API代码更简单一样, win32ui
(它封装了MFC)让这比 win32api
/win32gui
(它们封装了原始Win32 API)更简单。你可以找到很多相关的示例(例如,快速搜索“pywin32 msgproc example”会找到像 这个 的例子,搜索“python win32ui”等类似的词也能找到很多)。
不过,在这种情况下,你并不想让窗口像普通窗口那样工作,所以直接去底层写一个简单的消息循环可能更容易。不幸的是,找到这方面的示例代码比较困难——你基本上需要搜索C语言的原生API示例代码(比如在MSDN上查看 创建消息循环),然后再根据 pywin32
的文档将其翻译成Python。虽然这并不理想,尤其是如果你不懂C,但也不是特别难。这里有一个示例可以帮助你入门:
def msgloop():
while True:
msg = win32gui.GetMessage(None, 0, 0)
if msg and msg.message == win32con.WM_QUERYENDSESSION:
handle_shutdown()
win32api.TranslateMessage(msg)
win32api.DispatchMessage(msg)
if msg and msg.message == win32con.WM_QUIT:
return msg.wparam
worker = threading.Thread(real_program)
worker.start()
exitcode = msgloop()
worker.join()
sys.exit(exitcode)
我没有展示“如何创建一个最小的隐藏窗口”部分,或者如何用例如 threading.Condition
来通知工作线程停止,因为这些部分有很多更容易找到的好示例;这部分是比较难找的。