我有一个 Python (Windows 10) 脚本,其功能之一是创建备份。这是函数:
def create_backups(self, file: str, counter: int = None) -> None:
counter = counter or 1
res = self.re_obj.match(file)
if res is None or len(res.groups()) == 0:
back_file = f"{file} ({counter}).{self.ext}"
else:
l_res = re.search("\\w[\\w\\s]+?\\.[a-zA-Z_]\\w{2}", file)
file_name, file_ext = splitext(l_res.group())
back_file = f"{file_name}{file_ext} ({counter}).{self.ext}"
if exists(back_file) and counter < self.n_copies:
counter += 1
self.create_backups(back_file, counter)
with open(file, "rb") as f_src, open(back_file, "wb") as f_dst:
shutil.copy2(f_src, f_dst)
if self.verbose:
print(f"Copied {file} to '{back_file}'")
它应该制作多个副本(参数化)。如您所见,如果
back_file
已经存在,它会调用自身。模式如下:
test.txt
test.txt (1).sav
test.txt (2).sav
...
test.txt (n).sav
与
n
取决于参数
n_copies
如果我将其转换为
exe
文件,它仍然可以在
PowerShell
中工作。但是,如果我尝试从另一个程序运行它,它会在第二个副本上引发
PermissionError
异常
test.txt (1).sav
例如,我使用
FreeCommander XE
并且我尝试按如下方式运行脚本:
参数如下:
-
-f
文件名和 FreeCommander 替换%ActivSel%
与选择 -
-n
否。副本 -
-e
扩展名,例如sav
-
-b
备份方法
如果我从
PowerShell
运行等效的参数化脚本:
backup.exe -f "test.txt" -n 14 -e "sav"
一切正常。它位于
FreeCommander
我所在的位置
PermissionError
恰好在
shutil.copy2(f_src, f_dst)
我也尝试以管理员身份运行 FreeCommander 没有区别。
我是不知道如何解决这个问题。有什么想法吗?
编辑:调试详细信息:
Traceback (most recent call last):
File "backup.py", line 244, in <module>
File "backup.py", line 78, in create_backups
File "backup.py", line 79, in create_backups
PermissionError: [Errno 13] Permission denied: 'test.txt (2).sav'
[21056] Failed to execute script 'backup' due to unhandled exception!
这个问题很可能是由于文件锁定引起的。当你在
FreeCommander
中选择一个文件时,该文件可能还在被
FreeCommander
自身或其他程序占用,导致 Python 脚本无法写入该文件。
以下是一些可能的解决方案:
1. 关闭可能占用文件的程序:
在运行脚本之前,确保没有其他程序正在使用你要备份的文件。这包括
FreeCommander
自身。尝试先关闭
FreeCommander
,然后从命令行运行脚本,看看问题是否解决。
2. 使用文件复制库:
标准库中的
shutil.copy2()
函数可能会受到文件锁定的影响。你可以尝试使用更强大的文件复制库,例如
pywin32
,它可以更好地处理文件锁定情况。
以下是使用
pywin32
库复制文件的示例代码:
import win32file
import win32con
def create_backups(self, file: str, counter: int = None) -> None:
# ... (其他代码) ...
with open(file, "rb") as f_src:
with open(back_file, "wb") as f_dst:
# 使用 pywin32 复制文件
size = win32file.GetFileSize(f_src.fileno())
data = win32file.ReadFile(f_src.fileno(), size)[1]
win32file.WriteFile(f_dst.fileno(), data)
# 设置文件属性
win32file.SetFileAttributes(
back_file,
win32file.GetFileAttributes(file) & ~win32con.FILE_ATTRIBUTE_READONLY
)
# ... (其他代码) ...
3. 使用 try-except 块处理异常:
你可以使用
try-except
块来捕获
PermissionError
异常,并在遇到异常时尝试其他操作,例如:
- 等待一段时间后重试
- 提示用户关闭占用文件的程序
- 将文件复制到临时位置,然后再移动到目标位置
以下是一个使用
try-except
块处理异常的示例代码:
def create_backups(self, file: str, counter: int = None) -> None:
# ... (其他代码) ...
try:
with open(file, "rb") as f_src, open(back_file, "wb") as f_dst:
shutil.copy2(f_src, f_dst)
except PermissionError:
# 处理异常,例如:
# print(f"无法复制文件 '{file}',文件可能正在使用中。")
# time.sleep(5) # 等待 5 秒后重试
# raise # 重新抛出异常,让程序崩溃
# ... (其他代码) ...
4. 检查文件权限:
确保你的 Python 脚本有足够的权限写入目标文件夹。你可以尝试右键单击目标文件夹,选择“属性”,然后在“安全”选项卡中检查你的用户帐户是否具有“写入”权限。
其他建议:
- 使用调试器逐步执行代码,查看程序在哪个步骤出现问题。
- 在代码中添加日志记录,以便更好地了解程序的执行过程。
希望以上解决方案能够帮助你解决问题。如果问题仍然存在,请提供更多详细信息,例如:
- 你的 Python 版本
-
你使用的
pyinstaller
版本 - 完整的错误消息和堆栈跟踪信息