python怎么获取ftp服务器文件?

python连接ftp服务器,获取指定目录下的文件并下载,如果连接的时候指定utf-8编码,但是ftp服务器文件包含了非utf8编码的文件(ftp服务器上文件可能从windows上传存在gbk编码的文件),这样以下程序会报错'utf-8' codec can't decode byte 0xc6 in position 304: invalid continuation byte,除了限制上传的时候必须使用utf-8编码外,有其他办法来兼容吗?

import ftplib


ftp_cli = ftplib.FTP()
ftp_cli.encoding = 'utf-8'
ftp_cli.connect('10.21.x.x', 10021)
ftp_cli.login('ftpuser', 'ftpuser')

wdir = ''
file_list = []
ftp_cli.retrlines(f"LIST {wdir}", file_list.append)
print(file_list)
阅读 668
avatarAI BotBETA
import ftplib
import io

def decode_filename(filename):
    try:
        return filename.decode('utf-8')
    except UnicodeDecodeError:
        return filename.decode('gbk')

ftp_cli = ftplib.FTP()
ftp_cli.encoding = 'utf-8'
ftp_cli.connect('10.21.x.x', 10021)
ftp_cli.login('ftpuser', 'ftpuser')

wdir = ''
file_list = []
ftp_cli.retrlines(f"LIST {wdir}", file_list.append)
print(file_list)

for file in file_list:
    filename = decode_filename(file[3])  #获取文件名,注意,file[3]是文件名在返回结果中的位置,这个位置可能会因为FTP服务器和操作系统的不同而不同,你可能需要调整这个位置。
    with io.open(filename, 'wb') as f:  # 打开本地文件,准备写入数据
        ftp_cli.retrbinary(f"RETR {file[3]}", f.write)  # 从FTP服务器下载文件,并将数据写入本地文件。这里file[3]是文件名在返回结果中的位置,这个位置可能会因为FTP服务器和操作系统的不同而不同,你可能需要调整这个位置。

ftp_cli.quit()

在这个修改过的程序中,我增加了一个名为decode_filename的函数,这个函数会尝试将文件名从utf-8编码解码,如果解码失败,就尝试从gbk编码解码。然后在下载文件的时候,将文件名传递给这个函数进行解码。这样就可以处理包含非utf-8编码文件名的文件了。

1 个回答
新手上路,请多包涵

当处理FTP服务器上的文件时,如果服务器上的文件名包含了非UTF-8编码的字符(比如GBK编码的字符),而你尝试用UTF-8编码去解析这些文件名时,确实会遇到编码错误。这个问题在跨平台或跨语言环境的文件传输中非常常见。

为了解决这个问题,你可以尝试以下方法:

使用FTP服务器的默认编码:
一些FTP客户端库允许你指定或检测FTP服务器的默认编码。例如,使用ftplib库时,你可以尝试检测FTP服务器的编码,并使用该编码来处理文件名。但是,ftplib并不直接支持这种特性,你可能需要扩展它或寻找其他库。

尝试多种编码:
如果你可以确定服务器上可能使用的几种编码(比如UTF-8和GBK),你可以尝试用这些编码去解码文件名,直到成功为止。

使用第三方库:
有些第三方库可能提供了更好的编码支持或错误处理机制。例如,paramiko是一个提供SSH和SFTP功能的Python库,它可能更好地处理编码问题。

升级FTP服务器:
如果可能的话,升级FTP服务器以支持UTF-8编码是一个长期的解决方案。这样可以确保所有上传和下载的文件名都使用统一的编码格式。

避免使用特殊字符:
限制上传的文件名只使用ASCII字符可以避免编码问题。这可以通过文件上传的客户端来实现,确保在上传前对文件名进行清理或转换。

自定义错误处理:
在解码文件名时,你可以捕获UnicodeDecodeError异常,并尝试使用不同的编码来解码,或者简单地忽略或替换无法解码的字符。

下面是一个简单的例子,展示了如何使用ftplib库并尝试多种编码来解码文件名:

import ftplib  
  
def decode_filename(filename, encodings=['utf-8', 'gbk']):  
    for enc in encodings:  
        try:  
            return filename.decode(enc)  
        except UnicodeDecodeError:  
            pass  
    # 如果所有编码都尝试过了还是失败,可以抛出一个异常或返回原始字节  
    return filename  
  
ftp = ftplib.FTP('ftp.example.com')  
ftp.login('user', 'passwd')  
  
dir_list = ftp.nlst('/path/to/directory')  
for raw_filename in dir_list:  
    filename = decode_filename(raw_filename)  
    print(filename)  
    # 根据文件名下载文件...  
  
ftp.quit()
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题