ftplib编码问题:latin-1与utf-8冲突致FTP文件下载失败
解决FTP Latin-1编码文件下载至Azure Blob的问题
问题根源
你遇到的矛盾并非ftp.retrbinary本身不支持Latin-1——这个方法传输的是原始二进制数据,不会对文件内容做编码/解码操作。错误的本质是:
- 不设置
ftp.encoding = 'latin-1'时,ftp.nlst()用默认UTF-8解码Latin-1文件名,导致列文件失败; - 设置后,要么是构造RETR命令时编码传递出了问题,要么是后续的
is_stereo/convert_file_to_mono函数在处理音频元数据时,错误地用UTF-8解码Latin-1格式的内容。
解决方案
1. 修正RETR命令的编码传递
虽然设置了ftp.encoding = 'latin-1',但可以显式构造字节形式的RETR命令,避免ftplib自动编码的歧义:
# 替换原有的 ftp.retrbinary('RETR ' + original_file_name, ...) retr_command = b'RETR ' + original_file_name.encode('latin-1') ftp.retrbinary(retr_command, audio_buffer.write)
直接传递字节命令,确保服务器收到的文件名编码完全匹配Latin-1格式。
2. 检查音频处理函数的编码逻辑
错误信息里的解码失败,大概率来自is_stereo或convert_file_to_mono函数。这些函数如果读取音频元数据(比如ID3标签),必须用Latin-1解码:
# 示例:修正元数据解码逻辑 metadata_bytes = audio_stream.read(128) metadata_str = metadata_bytes.decode('latin-1') # 不要用utf-8
3. 可选:手动获取文件名列表
如果ftp.nlst()的编码处理仍不稳定,可以直接获取原始字节形式的文件名再解码:
# 替换原有的 files = ftp.nlst() files = [] ftp.voidcmd('TYPE A') # 切换到ASCII模式获取文本响应 ftp.retrlines('NLST', lambda line: files.append(line.decode('latin-1')))
修正后的完整代码
def download_audios_from_ftp_to_azure_blob(ftp_details, connection_name, container_name): ftp = FTP(ftp_details['host']) ftp.login(ftp_details['username'], ftp_details['password']) ftp.set_pasv(True) ftp.encoding = 'latin-1' ftp.cwd(ftp_details['remote_directory']) blob_service_client = BlobServiceClient.from_connection_string(connection_name) container_client = blob_service_client.get_container_client(container_name) # 手动获取Latin-1编码的文件名列表 files = [] ftp.voidcmd('TYPE A') ftp.retrlines('NLST', lambda line: files.append(line.decode('latin-1'))) df_files = pd.DataFrame(files, columns=['file_name']) for _, row in df_files.iterrows(): original_file_name = row["file_name"] with BytesIO() as audio_buffer: # 显式构造Latin-1编码的RETR命令 retr_cmd = b'RETR ' + original_file_name.encode('latin-1') ftp.retrbinary(retr_cmd, audio_buffer.write) audio_buffer.seek(0) if is_stereo(audio_buffer): # 确保convert_file_to_mono使用Latin-1处理元数据 audio_buffer = convert_file_to_mono(audio_buffer) blob_client = container_client.get_blob_client(blob=original_file_name) blob_client.upload_blob(audio_buffer, overwrite=True) ftp.quit()
关键注意点
- FTP的
encoding参数只负责命令和响应字符串的编码,和文件内容的二进制传输无关; - Azure Blob支持UTF-8文件名,直接传递包含
ñ的字符串即可,无需额外转换; - 所有涉及文件名或音频元数据的解码操作,统一用
latin-1编码。
内容的提问来源于stack exchange,提问作者Pablo González González
相关产品推荐
相关产品推荐

