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

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时生成空文件。

另外还有两个次要问题:

  1. 变量名拼写错误:SourcPath应该是SourcePath,调用decrypt时传入的参数名和函数定义的参数名不匹配
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 16:05:42