有没有一种简单的方法来解决Delphi utf8的问题
我发现(困难的方式),如果文件具有有效的UTF-8 BOM但包含任何无效的UTF8编码,并且可以通过任何Delphi(2009+)编码启用的方法(如LoadFromFile
)读取,则结果是一个完全空的文件,没有错误指示。 在我的几个应用程序中,我宁愿仅仅丢失一些不好的编码,即使在这种情况下我也没有收到错误报告。
调试显示MultiByteToWideChar
被调用两次,首先得到输出缓冲区大小,然后进行转换。 但是TEncoding.UTF8包含这些调用的私有FMBToWCharFlags
值,并且这是使用MB_ERR_INVALID_CHARS
值初始化的。 所以获取charcount的调用返回0,并且加载的文件完全是空的。 在没有标志的情况下调用这个API会'悄然丢弃非法代码点'。
我的问题是如何最好地通过Encoding区域中的类嵌套来解决事实,即这是一个私有值(因为它是所有线程的类变量,所以需要这样做)。 我想我可以使用Marco Cantu的Delphi 2009书中的指导来添加自定义的UTF8编码。 如果MultiByteToWideChar
在没有标志的情况下再次调用它时返回了编码错误,它可以选择引发异常。 但是这并不能解决如何使用自定义编码而不是Tencoding.UTF8
。
如果我可以在初始化时将它设置为应用程序的默认值,可能通过实际修改Tencoding.UFT8
的类var,这可能就足够了。
当然,我需要一个解决方案,而无需等待提交质量控制报告,要求提供更强大的设计,让它接受,并看到它改变。
任何想法都会非常受欢迎。 有人可以证实,这仍然是XE4的问题,我还没有安装?
当我第一次更新Indy来支持TEncoding
,我遇到了MB_ERR_INVALID_CHARS
问题,最后为UTF-8处理实现了一个自定义的TEncoding
- MB_ERR_INVALID_CHARS
类,以避免指定MB_ERR_INVALID_CHARS
。 我没想过要使用班级帮手。
但是,这个问题不仅限于UTF-8。 任何TEncoding
类的任何解码失败都会导致空白结果,而不是引发异常。 为什么Embarcadero选择了这种路线,当大多数RTL / VCL使用异常时,这种情况超出了我的想象。 没有提出错误例外导致Indy中相当多的问题必须解决。
这可以很简单地完成,至少在Delphi XE5中(没有检查早期版本)。 只是实例化你自己的TUTF8Encoding
:
procedure LoadInvalidUTF8File(const Filename: string);
var
FEncoding: TUTF8Encoding;
begin
FEncoding := TUTF8Encoding.Create(CP_UTF8, 0, 0);
// Instead of CP_UTF8, MB_ERR_INVALID_CHARS, 0
try
with TStringList.Create do
try
LoadFromFile(Filename, FEncoding);
// ...
finally
Free;
end;
finally
FEncoding.Free;
end;
end;
这里唯一的问题是,新实例化的TUTF8Encoding
的IsSingleByte
属性被错误地设置为False
,但是这个属性目前在Delphi源码的任何地方都没有使用。
部分解决方法是强制UTF8编码全局抑制MB_ERR_INVALID_CHARS
。 对于我来说,这避免了引发异常的需要,因为我发现它使MultiByteToWideChar
不太“沉默”:它实际上插入了$fffd
字符(Unicode'替换字符'),然后我可以在重要的情况下找到它。 以下代码执行此操作:
unit fixutf8;
interface
uses System.Sysutils;
type
TUTF8fixer = class helper for Tmbcsencoding
public
procedure setflag0;
end;
implementation
procedure TUTF8fixer.setflag0;
{$if CompilerVersion = 31}
asm
XOR ECX,ECX
MOV Self.FMBToWCharFlags,ECX
end;
{$else}
begin
Self.FMBToWCharFlags := 0;
end;
{$endif}
procedure initencoding;
begin
(Tencoding.UTF8 as TmbcsEncoding).setflag0;
end;
initialization
initencoding;
end.
一个更有用的原则性修复需要将对MultiByteToWideChar
的调用更改为不使用MB_ERR_INVALID_CHARS
,并使用此标志进行初始调用,以便在加载完成后引发异常,以指示字符将被替换。
在这个问题上有相关的质量控制报告,包括76571,79042和111980.第一个已经“按设计”解决。
(编辑与德尔福柏林合作)
链接地址: http://www.djcxy.com/p/16169.html