Python+Gnupg解密SFTP下载文件时生成空文件的问题
问题描述
我编写了一段Python脚本,功能是从SFTP服务器下载GPG文件至Windows本地目录,备份加密文件后将其解密到指定目录。目前脚本的下载、备份功能均正常,但解密生成的文件始终为空。我是Python新手,怀疑是文件写入环节出现问题,求帮忙排查。
相关代码如下:
import pysftp import gnupg #dycription import os ############## Decryption variables KeyPath=(r"C:\winuser\test\key"+slash) KeyFile=(r"C:\winuser\test\sbp.asc") DecryptedPath=(r"C:\winuser\test\Deycrpt"+slash) SourcPath=(r"C:\winuser\test"+slash) ArchivePath=(r"C:\winuser\test"+slash) def ConnectSFTP(server, port, username, password, cnopts): def DownloadSFTP(RemotePath, end, LocalPath,newsftp): def decrypt(KeyPath, KeyFile, DecryptedPath, SourcePath, ArchivePath, ls): gpg = gnupg.GPG(gnupghome=KeyPath) gpg.import_keys(open(KeyFile).read()) for f in ls: with open(SourcePath+f, 'rb') as fh: status = gpg.decrypt_file(fh, output=f[:-4]) outfile = DecryptedPath+f[:-4] with open(outfile,"wb") as fo: fo.write(status.data) #os.rename(DecryptedPath+f[:-4], DecryptedPath+f[:-4]+status.extension) os.rename(SourcePath+f, ArchivePath+f) return True with ConnectSFTP(host, port, username, password, cnopts) as newsftp: ls = DownloadSFTP(RemotePath, end,LocalPath,newsftp) decrypt(KeyPath, KeyFile, DecryptedPath, SourcPath, ArchivePath, ls) print(ls)
问题排查与解决方案
核心问题
你的解密逻辑存在重复操作:
当调用gpg.decrypt_file(fh, output=f[:-4])时,python-gnupg会直接把解密内容写入当前工作目录下的f[:-4]文件,此时status.data不会存储解密后的内容,导致后续手动写入outfile时生成空文件。
另外还有两个次要问题:
- 变量名拼写错误:
SourcPath应该是SourcePath,调用decrypt时传入的参数名和函数定义的参数名不匹配 slash变量未定义,Windows环境下建议用os.sep替代,避免路径拼接错误
修正后的代码(推荐方案)
去掉output参数,通过status.data手动写入目标路径,同时修正拼写和路径问题:
import pysftp import gnupg import os ############## Decryption variables slash = os.sep # 定义路径分隔符,适配Windows KeyPath = fr"C:\winuser\test\key{slash}" KeyFile = r"C:\winuser\test\sbp.asc" DecryptedPath = fr"C:\winuser\test\Deycrpt{slash}" SourcePath = fr"C:\winuser\test{slash}" # 修正拼写错误 ArchivePath = fr"C:\winuser\test{slash}" def ConnectSFTP(server, port, username, password, cnopts): # 补充SFTP连接逻辑,返回pysftp.Connection对象 return pysftp.Connection(server, port=port, username=username, password=password, cnopts=cnopts) def DownloadSFTP(RemotePath, end, LocalPath, newsftp): # 补充下载逻辑,返回下载的文件名列表 ls = newsftp.listdir(RemotePath) target_files = [f for f in ls if f.endswith(end)] for f in target_files: remote_file = os.path.join(RemotePath, f) local_file = os.path.join(LocalPath, f) newsftp.get(remote_file, local_file) return target_files def decrypt(KeyPath, KeyFile, DecryptedPath, SourcePath, ArchivePath, ls): gpg = gnupg.GPG(gnupghome=KeyPath) # 确认密钥导入状态 import_result = gpg.import_keys(open(KeyFile).read()) print(f"密钥导入结果:{import_result}") # 确保解密目录存在 os.makedirs(DecryptedPath, exist_ok=True) for f in ls: source_file = os.path.join(SourcePath, f) with open(source_file, 'rb') as fh: # 不指定output参数,解密数据存入status.data status = gpg.decrypt_file(fh) # 检查解密是否成功 if status.ok: outfile = os.path.join(DecryptedPath, f[:-4]) with open(outfile, "wb") as fo: fo.write(status.data) print(f"文件{f}解密成功,保存至{outfile}") # 备份原加密文件 os.rename(source_file, os.path.join(ArchivePath, f)) else: print(f"文件{f}解密失败:{status.stderr}") return True # 补充SFTP连接参数(根据实际情况填写) host = "your_sftp_host" port = 22 username = "your_username" password = "your_password" cnopts = pysftp.CnOpts() # 若需忽略主机密钥验证,添加:cnopts.hostkeys = None with ConnectSFTP(host, port, username, password, cnopts) as newsftp: RemotePath = "/remote/path" end = ".gpg" # 匹配下载的GPG文件后缀 LocalPath = SourcePath ls = DownloadSFTP(RemotePath, end, LocalPath, newsftp) decrypt(KeyPath, KeyFile, DecryptedPath, SourcePath, ArchivePath, ls) print(ls)
额外注意事项
- 确认GPG密钥文件
sbp.asc是有效的私钥,且有权限解密目标GPG文件 - 通过
status.ok和status.stderr可快速定位解密失败原因(如密钥不匹配、文件损坏等) - 确保
ArchivePath对应的目录已存在,避免备份时报错
内容的提问来源于stack exchange,提问作者Stephen Palmore
相关产品推荐
相关产品推荐

