- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想将任意二进制数据作为 BLOB 存储到 SQlite 数据库中。
数据将通过此函数添加为值
:
procedure TSQLiteDatabase.AddParamText(name: string; value: string);
现在我想将 WideString
转换为其 UTF8 表示形式,以便可以将其存储到数据库中。调用UTF8Encode
并将结果存储到数据库后,我注意到数据库内的数据不是UTF8解码的。相反,它在我的计算机区域设置中被编码为 AnsiString。
我运行了以下测试来检查发生了什么:
type
{$IFDEF Unicode}
TBinary = RawByteString;
{$ELSE}
TBinary = AnsiString;
{$ENDIF}
procedure TForm1.Button1Click(Sender: TObject);
var
original: WideString;
blob: TBinary;
begin
original := 'ä';
blob := UTF8Encode(original);
// Delphi 6: ä (as expected)
// Delphi XE4: ä (unexpected! How did it do an automatic UTF8Decode???)
ShowMessage(blob);
end;
字符“ä”转换为 UTF8 后,内存中的数据是正确的(“¤”),但是,一旦我将 TBinary
值传递给函数(如string
或 AnsiString
),Delphi XE4 出于某种我不知道的原因执行了调用 UTF8Decode 的“神奇类型转换”。
我已经找到了避免这种情况的解决方法:
function RealUTF8Encode(AInput: WideString): TBinary;
var
tmp: TBinary;
begin
tmp := UTF8Encode(AInput);
SetLength(result, Length(tmp));
CopyMemory(@result[1], @tmp[1], Length(tmp));
end;
procedure TForm1.Button2Click(Sender: TObject);
var
original: WideString;
blob: TBinary;
begin
original := 'ä';
blob := RealUTF8Encode(original);
// Delphi 6: ä (as expected)
// Delphi XE4: ä (as expected)
ShowMessage(blob);
end;
但是,使用 RealUTF8Encode
的解决方法对我来说看起来很脏,我想了解为什么简单调用 UTF8Encode
不起作用,以及是否有更好的解决方案。
最佳答案
在 Delphi 的 Ansi 版本(D2009 之前)中,UTF8Encode()
返回 UTF-8 编码的 AnsiString
。在 Unicode 版本(D2009 及更高版本)中,它返回一个 UTF-8 编码的 RawByteString
,并为其分配了 CP_UTF8
(65001) 代码页。
在 Ansi 版本中,ShowMessage()
采用 AnsiString
作为输入,而 UTF-8 字符串是 AnsiString
,因此它得到按原样显示。在 Unicode 版本中,ShowMessage()
采用 UTF-16 编码的 UnicodeString
作为输入,因此 UTF-8 编码的 RawByteString
会转换为 UTF- 16 使用其指定的 CP-UTF8
代码页。
如果您实际上将 blob
数据直接写入数据库,您会发现它可能是也可能不是 UTF-8 编码,具体取决于您的写入方式。但你的做法是错误的;在这种情况下,使用 RawByteString
是不正确的。 RawByteString
仅用作过程参数。不要将其用作局部变量。这就是你的问题的根源。来自 documentation :
The purpose of RawByteString is to reduce the need for multiple overloads of procedures that read string data. This means that parameters of routines that process strings without regard for the string's code page should typically be of type RawByteString.
RawByteString should only be used as a parameter type, and only in routines which otherwise would need multiple overloads for AnsiStrings with different codepages. Such routines need to be written with care for the actual codepage of the string at run time.
对于 Unicode 版本的 Delphi,我建议您使用 TBytes
来代替 RawByteString
来保存 UTF-8 数据,并使用 TEncoding 对其进行编码
:
var
utf8: TBytes;
str: string;
...
str := ...;
utf8 := TEncoding.UTF8.GetBytes(str);
您正在寻找一种在传递时不执行隐式文本编码的数据类型,而 TBytes
就是这种类型。
对于 Ansi 版本的 Delphi,您可以完全按照您的方式使用 AnsiString
、WideString
和 UTF8Encode
。
但就我个人而言,我建议对 UTF-8 数据一致使用 TBytes
。因此,如果您需要一个支持 Ansi 和 Unicode 编译器的单一代码库(呃!),那么您应该创建一些帮助程序:
{$IFDEF Unicode}
function GetUTF8Bytes(const Value: string): TBytes;
begin
Result := TEncoding.UTF8.GetBytes(Value);
end;
{$ELSE}
function GetUTF8Bytes(const Value: WideString): TBytes;
var
utf8str: UTF8String;
begin
utf8str := UTF8Encode(Value);
SetLength(Result, Length(utf8str));
Move(Pointer(utf8str)^, Pointer(Result)^, Length(utf8str));
end;
{$ENDIF}
Ansi 版本产生的堆分配超出了所需的数量。您可能会选择编写一个直接调用 WideCharToMultiByte()
的更高效的帮助程序。
在 Delphi 的 Unicode 版本中,如果由于某种原因您不想对 UTF-8 数据使用 TBytes
,则可以使用 UTF8String
代替。这是一个特殊的 AnsiString
,始终使用 CP_UTF8
代码页。然后你可以写:
var
utf8: UTF8String;
str: string;
....
utf8 := str;
编译器会在后台为您从 UTF-16 转换为 UTF-8。不过我不推荐这样做,因为它在移动平台或 Delphi 的 Ansi 版本中不受支持(UTF8String
自 Delphi 6 以来就已存在,但直到 Delphi 2009 为止它都不是真正的 UTF-8 字符串)。这就是为什么我建议您使用 TBytes
的原因之一。我的理念是,至少在 Unicode 时代,存在 native string
类型,任何其他编码都应保存在 TBytes
中。
关于delphi - 从 RawByteString 转换为字符串会自动调用 UTF8Decode 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24057569/
请在标记为重复之前阅读。 我正在创建一组依赖智能卡进行身份验证的应用程序。到目前为止,每个应用程序都单独控制智能卡读卡器。几周后,我的一些客户将同时使用多个应用程序。因此,我认为创建一个控制身份验证过
我想设置一个小程序,从数据库中检索信息,然后根据请求将该信息分发给另一个程序。例如,一个名为“Master”的程序将从数据库中检索数据并创建一个对象集合(列表、数组等,无论哪种效果最好),然后一个名为
我有两台电脑,都装有 XE2。我以为我在两者上安装了相同的安装,但在其中一个上安装第 3 方软件包时遇到问题,而另一个则正常。 无论如何,我希望两者都一样。最简单的人可能只是通过移入我的 Dropbo
有冲突吗? 最佳答案 所有新版本的 Delphi 始终可以安全地安装到旧版本的下一个版本。 每个新版本都应安装在其自己的目录中。 如果您要安装多个版本,请始终先安装最旧的版本,然后再安装最新版本。 我
快速提问:如果我从代码中删除 // 或 (* *) 中的注释,Delphi 2007 的执行时间会受到影响吗?最终结果是一个可能包含数千行注释的 EXE 文件。 最佳答案 编译器会简单地忽略注释,并且
我必须对照另一个文件检查文件的每一行。 如果第二个文件中存在第一个文件中的一行,则必须删除它。 现在,我正在使用2个列表框,并且“对于listbox1.items.count-1可以开始...” 我的
我正在尝试在访问数据库中添加一些数据。但是我有麻烦,因为这会返回错误: ADOQuery1 missing sql property 实现了对代码的几次修改,到目前为止没有任何效果。 我究竟做错了什么
我用Delphi 5编写了一个程序,在Windows 8 32位PC上可以正常运行。我发现在Windows 7 64位笔记本电脑上运行它最终会导致reallocmem错误,而该错误在32位PC上不会发
看来这是我需要的工具,用于提取XML并与TClientDataset连接。我已经在几篇文章和文档中看到了它,但是我无法在XE2组件列表中找到它-在任何地方!应该在哪里?是否在可能未安装的可选软件包中?
我正在寻找一个非常通用的TDBTree组件,我想听听一些建议。我正在特别寻找一种显示主记录和“ n”个链接表记录的记录。 (我的意思是来自各个表的记录)。例如,TDBTree将钩接到主表,明细表1,附
我需要将按钮制作成旋转三角形的形状(或者说是任何多边形)。谁能提供任何建议? 最佳答案 查看Win32 API CreatePolygonRgn()和SetWindowRgn()函数,以创建一个HRG
你好专家 我的JvPasswordForm1有一个旧的JVC组件。 似乎该组件不再存在:它替换为哪个组件? 重新获得 最佳答案 尝试查找TJvLoginDialog,TjvPassword已合并到其中
几天前,我已经设置了我的开发环境(在装有Win 7的VM和域上的用户的VM上安装了delphi 2009),并安装了我的组件(jedi's,devExpress,ADS等)。 今天,我启动机器,打开d
开始对控件进行子分类的正确位置/时间是什么? 恢复原始窗口proc的正确时间是几点? 现在我在表单创建过程中子类化: procedure TForm1.FormCreate(Sender: TObje
有人可以给我一些有关如何登录访问的网页(使用任何网络浏览器)的指示吗?我应该建立一个全球代理....钩住网络....吗?我需要记录的只是页面地址,而不是其中包含的信息。 我正在使用Delphi。 谢谢
我创建了一个像 TMyClass = class(TObject) private FList1: TObjectList; FList2: TObjectList; public end;
我有一个BPG文件,我已对其进行修改以用作我们公司的自动构建服务器的make文件。为了使其正常工作,我必须进行更改 用途*用途 'unit1.pas'中的unit1 * unit1 'unit2.pa
我将Delphi 7代码迁移到了Delphi XE4。我在Delphi XE4的LoadFromStram方法中遇到错误,但对于Delphi 7来说也可以正常工作。 错误: First chance
我正在尝试学习一些新技巧,以便更好地组织我在 Delphi 中的单元中的一些源代码。 我注意到我访问的一些函数或方法似乎是类中的类,但是我还没有成功地在类中创建一个工作类,虽然它编译得很好,但在执行代
我有一个包含许多类的大单元,现在我想通过将某些类分成新的单元来重构该单元。 我不得不承认我缺乏使用Delphi内置IDE功能的经验。利用内置功能“查找|查找对类型的本地引用”并没有多大帮助,因为类方法
我是一名优秀的程序员,十分优秀!