使用IdFTP
,我连接的服务器不是使用UTF-8,而是使用ANSI。我的代码没什么特别之处,只需设置Host
,Username
,Password
和连接到服务器。然后我调用没有参数的List
方法。迭代DirectoryListing
会给出错误的文件名结果。我在本地代码页(CP-1250)中编码的示例目录名是:
aąęsśćńółżźz
我以为我能够通过将文件名字段转换为AnsiString
并设置代码页来“修复”文件名字段,但它似乎已经被破坏了 - DirectoryListing[I].FileName
的内存转储:
a ? ? s ? ? ? ?? ?? z 6100 FDFF FDFF 7300 FDFF FDFF FDFF 8FDB DFDF 7A00
使用GIdDefaultAnsiEncoding
或IOHandler.DefStringEncoding
进行操作(在连接之后,在列表之前)没有任何区别。我不想弄乱IdFTP
或IdGlobal
代码,因为我正在将其与其他涉及Unicode的项目一起使用,这些工作完美无缺。 Delphi XE2或XE7。
正如您所看到的,FData
包含每个字符串2个字节的原始文件名:
即使我将IOHandler.DefStringEncoding
设置为TIdTextEncoding
,FIsSingleByte = True
的任何FMaxCharSize = 1
。然而它看起来很有希望,因为#$ 009F在CP-1250中是“ź”,但我不是在寻找每服务器,临时解决方案。我希望Indy在根据服务器功能(UTF-8或具有指定编码的ANSI)设置IOHandler.DefStringEncoding
和GIdDefaultAnsiEncoding
后正确处理此问题。
Total Commander连接日志:
答案 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()
在解析它之前在内部执行的操作)。所以问题是:
您的FTP服务器首先没有正确地将目录名从CP-1250转换为UTF-8。考虑到Total Commander似乎能够正确处理列表,这是不可能的。
TIdFTP
在解析之前未正确存储原始UTF-8八位位组数据。这种可能性更大。
很难说实际上是哪种情况,因为您没有显示实际传输的原始列表数据。并且您没有指定您正在使用的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
FTP列表完成后,我会通过从FileName
中提取文件名的函数覆盖Data
属性,然后使用正确的代码页将String转换为RawByteString。仅当服务器不支持UTF-8时才应用修复。通过这种方式,我可以快速移动FTP - ChangeDir
,Get
,Put
等等。