Python 3.5, ftplib

ftp.nlst() get file names? And how to bring them to normal appearance?

 filelist = ftp.nlst() - ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ список ΠΈΠΌΠ΅Π½ Ρ„Π°ΠΉΠ»ΠΎΠ² print (filelist[3]) - Π²Ρ‹Π²ΠΎΠ΄ΠΈΠΌ имя 4-ΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π° ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΠΈΠ΅Ρ€ΠΎΠ³Π»ΠΈΡ„Ρ‹ 

@jfs >>> print(ascii(filelist[6])) '\xc8\xed\xf1\xf2\xf0\xf3\xea\xf6\xe8\xff.pdf'

Thanks for the detailed answer)

  • To eliminate problems with displaying non-ASCII strings in your environment, show print(ascii(filelist[3])) to help with debugging. What does ftp.encoding show? - jfs
  • @jfs >>> print (ascii (filelist [6])) '\ xc8 \ xed \ xf1 \ xf2 \ xf0 \ xf3 \ xea \ xf6 \ xe8 \ xff - Dr.Z
  • association: stackoverflow.com/questions/29523067/… - Nicolas Chabanovsky ♦

1 answer 1

Initially (RFC 765, 959), FTP only 7-bit ASCII supported, RFC 2640 extends support to other encodings, RFC 3659 specifies that commands such as MLST can return paths either in UTF-8 encoding, or it can be an arbitrary byte porridge - With some exceptions such as CRLF (new line, b'\x0d\x0a' ), single IAC Telnet ( b'\xff' ).

On POSIX, file names can be an arbitrary sequence of bytes with the exception of b'\x2f' and b\x00' (slash and zero).

In Python 3, ftplib formally uses latin-1's default encoding, which allows decoding an arbitrary sequence of bytes in Unicode.

Q: How does ftp.nlst () get file names?

ftp.nlst() returns a list of text (Unicode) strings.

Q: And how to bring them to normal appearance?

If you know that the server uses a unique encoding for the file names in your case (probably, utf-8 , if the output of the feat command shows it) and there are no unrepresentable names (PEP 383) , then the correct names can be obtained by decoding:

 filename = filename.encode(ftp.encoding).decode(your_encoding) 

You can pass the 'surrogateescape' error handler in .decode() to support non-representable names (so that you can restore the original bytes without loss, while at the same time allowing you to print the representable names in "normal form").


Judging by the result of ascii() , in your case, the ftp server returns the names in cp1251 encoding (ANSI codepage on Russian Windows):

 >>> print(ascii(filelist[6])) '\xc8\xed\xf1\xf2\xf0\xf3\xea\xf6\xe8\xff' 

In this case, your_encoding='cp1251' to get the original name:

 filename = filelist[6].encode(ftp.encoding).decode('cp1251') # -> 'Π˜Π½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡ' 

In order not to re-encode in vain, you can set before calling ftp.nlst()
ftp.encoding = 'cp1251' , if it is known that all file names in this encoding are representable. Then ftp.nlst() will immediately return correctly decoded names.