Delphi IdFTP - 获取在指定的ANSI代码页中编码的文件列表

时间:2015-03-31 14:42:29

标签: delphi

使用IdFTP,我连接的服务器不是使用UTF-8,而是使用ANSI。我的代码没什么特别之处,只需设置HostUsernamePassword和连接到服务器。然后我调用没有参数的List方法。迭代DirectoryListing会给出错误的文件名结果。我在本地代码页(CP-1250)中编码的示例目录名是:

  

aąęsśćńółżźz

我以为我能够通过将文件名字段转换为AnsiString并设置代码页来“修复”文件名字段,但它似乎已经被破坏了 - DirectoryListing[I].FileName的内存转储:

a    ?    ?    s    ?    ?    ?    ??   ??   z 
6100 FDFF FDFF 7300 FDFF FDFF FDFF 8FDB DFDF 7A00

使用GIdDefaultAnsiEncodingIOHandler.DefStringEncoding进行操作(在连接之后,在列表之前)没有任何区别。我不想弄乱IdFTPIdGlobal代码,因为我正在将其与其他涉及Unicode的项目一起使用,这些工​​作完美无缺。 Delphi XE2或XE7。

正如您所看到的,FData包含每个字符串2个字节的原始文件名:

enter image description here

即使我将IOHandler.DefStringEncoding设置为TIdTextEncodingFIsSingleByte = True的任何FMaxCharSize = 1。然而它看起来很有希望,因为#$ 009F在CP-1250中是“ź”,但我不是在寻找每服务器,临时解决方案。我希望Indy在根据服务器功能(UTF-8或具有指定编码的ANSI)设置IOHandler.DefStringEncodingGIdDefaultAnsiEncoding后正确处理此问题。

Total Commander连接日志:

enter image description here

2 个答案:

答案 0 :(得分:4)

您的服务器支持MLSD命令。 Total Commander正在发送MLSD命令而不是旧的LIST命令。这很好,因为MLSD具有标准化格式(请参阅RFC 3659),其中包括对嵌入式字符集信息的支持。如果没有明确说明字符集,则必须使用UTF-8。

您没有显示TIdFTP的命令/响应日志,但TIdFTPListItem.Data属性显示MLSD格式化输出数据的事实意味着TIdFTP.List()也在使用MLSD命令(通过内部调用TIdFTP.ExtListDir())。显示的输出不包含明确的charset属性,因此TIdFTP会将文件名解码为UTF-8。

但是TIdFTPListItem.Data属性中显示的原始文件名数据不是您显示的目录名的正确UTF-8编码形式(即使作为原始文件存储) 8位编码UnicodeString - 这是TIdFTP.ExtListDir()在解析它之前在内部执行的操作)。所以问题是:

  1. 您的FTP服务器首先没有正确地将目录名从CP-1250转换为UTF-8。考虑到Total Commander似乎能够正确处理列表,这是不可能的。

  2. TIdFTP在解析之前未正确存储原始UTF-8八位位组数据。这种可能性更大。

  3. 很难说实际上是哪种情况,因为您没有显示实际传输的原始列表数据。并且您没有指定您正在使用的Delphi和Indy的确切版本。假设服务器正在正确传输UTF-8,您可能只是使用不能正确处理UTF-8传输的较旧的Indy版本。 AFAIK,当前版本(撰写本文时为10.6.2.5270)应该能够处理它,只要您使用Delphi 2009或更高版本。如果您可以提供Wireshark捕获原始列表数据,我可以检查TIdFTP中是否存在需要修复的逻辑问题。

答案 1 :(得分:0)

我的团队正在寻找我必须提供的快速解决方案。我的解决方案基于以下帖子:http://forums2.atozed.com/viewtopic.php?p=32301#p32301和此问题:Converting UnicodeString to AnsiString

enter image description here FTP列表完成后,我会通过从FileName中提取文件名的函数覆盖Data属性,然后使用正确的代码页将String转换为RawByteString。仅当服务器不支持UTF-8时才应用修复。通过这种方式,我可以快速移动FTP - ChangeDirGetPut等等。