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

使用pysftp/paramiko调用listdir_attr遇UnicodeDecodeError求助

解决SFTP listdir_attr UnicodeDecodeError问题

核心原因

报错的0xa0字节是Latin-1编码里的不间断空格,说明SFTP服务器返回的文件名并非严格UTF-8编码,而pysftp/paramiko默认强制用UTF-8解码,导致解码失败。Cyberduck能正常访问是因为它自动适配了服务器的编码规则。

可行解决思路

1. 强制指定SFTP会话的文件名编码

直接修改paramiko SFTP客户端的默认编码为服务器实际使用的编码(比如Latin-1/cp1252,这俩对0xa0都兼容),跳过UTF-8强制解码:

import paramiko

# 建立SSH连接
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("your_host", username="your_user", password="your_pass")

# 初始化SFTP客户端并修改编码
sftp = ssh.open_sftp()
sftp._encoding = "latin-1"  # 替换为服务器实际编码,比如cp1252、gbk等

# 现在可正常调用listdir_attr
file_list = sftp.listdir_attr("your_remote_directory")
for file in file_list:
    print(file.filename)  # 输出保留原始文件名格式

# 用完记得关闭连接
sftp.close()
ssh.close()

2. 直接获取原始字节文件名(彻底绕开自动解码)

如果不确定服务器编码,直接获取文件名的原始字节数据,再手动处理解码逻辑,完全保留原始文件名:

import paramiko
from paramiko.sftp import SFTP_OPENDIR, SFTP_READDIR, SFTP_CLOSE

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("your_host", username="your_user", password="your_pass")
sftp = ssh.open_sftp()

remote_dir = "/your/remote/directory"
handle = sftp._request(SFTP_OPENDIR, remote_dir)
try:
    while True:
        msg = sftp._request(SFTP_READDIR, handle)
        if not msg:
            break
        for attr in msg:
            # 获取未解码的原始字节文件名
            raw_filename_bytes = attr.filename_bytes
            # 自定义解码逻辑:优先UTF-8,失败则用Latin-1兜底
            try:
                filename = raw_filename_bytes.decode("utf-8")
            except UnicodeDecodeError:
                filename = raw_filename_bytes.decode("latin-1")
            print(f"文件名: {filename}, 大小: {attr.st_size}")
finally:
    sftp._request(SFTP_CLOSE, handle)
    sftp.close()
    ssh.close()

3. 用字节路径直接操作文件(保留原始文件名)

如果需要对文件进行下载/上传操作,直接使用字节形式的远程路径,完全避免编码解码环节,确保原始文件名不被篡改:

# 承接上面的代码,raw_filename_bytes是原始字节文件名
remote_file_path = remote_dir.encode("utf-8") + b"/" + raw_filename_bytes
# 下载文件到本地
with open("local_file.bin", "wb") as f:
    sftp.getfo(remote_file_path, f)

4. 检查SFTP服务器编码配置

如果有权限,查看SFTP服务器的编码设置(比如OpenSSH的sftp-server配置),确认服务器使用的文件名编码,在代码中精准匹配,这是最彻底的解决方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 15:13:41