使用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
相关产品推荐
相关产品推荐

