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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 23:22:07