如何从 UnicodeString 加载 TMemoryStream
How to load a TMemoryStream from a UnicodeString
我试图用计算出的 RTF 文件的字符串填充 DevExpress VCL TdxRichEditControl
,而没有花时间保存文件。所以,这是一个演示项目:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
UnicodeString txt = "{\rtf1\deff0{\fonttbl{\f0 Calibri;}{\f1 Arial Unicode MS;}{\f2 Britannic Bold;}}{\colortbl ;\red0\green0\blue255 ;\red255\green0\blue0 ;}{\*\defchp \fs22}{\*\defpap \sl275\slmult1\sa200}{\stylesheet {\ql\sl275\slmult1\sa200\fs22 Normal;}{\*\cs1\fs22 Default Paragraph Font;}{\*\cs2\sbasedon1\fs22 Line Number;}{\*\cs3\ul\fs22\cf1 Hyperlink;}{\*\ts4\tsrowd\fs22\ql\sl275\slmult1\sa200\tscellpaddfl3\tscellpaddl108\tscellpaddfb3\tscellpaddfr3\tscellpaddr108\tscellpaddft3\tsvertalt\cltxlrtb Normal Table;}{\*\ts5\tsrowd\sbasedon4\fs22\ql\sl275\slmult1\sa200\trbrdrt\brdrs\brdrw10\trbrdrl\brdrs\brdrw10\trbrdrb\brdrs\brdrw10\trbrdrr\brdrs\brdrw10\trbrdrh\brdrs\brdrw10\trbrdrv\brdrs\brdrw10\tscellpaddfl3\tscellpaddl108\tscellpaddfr3\tscellpaddr108\tsvertalt\cltxlrtb Table Simple 1;}}{\*\listoverridetable}\nouicompat\splytwnine\htmautsp\sectd\pard\plain\ql\sl275\slmult1\sa200{\f1\fs28\cf1 This is in blue }{\b\i\f2\fs40\cf2 Red bold}\b\i\fs22\cf2\par}";
TMemoryStream *AStream = new TMemoryStream();
AStream->WriteBuffer(txt.c_str(), txt.Length());
AStream->Position = 0;
AStream->SaveToFile("C:/Trash/Test.rtf");
AStream->Position = 0;
dxRichEditControl1->Document->InsertDocumentContent(dxRichEditControl1->Document->Range->Start, AStream, TdxRichEditDocumentFormat::Rtf);
AStream->Free();
}
我在这个演示中将它保存到一个文件中以查看出了什么问题,发现该文件在每个其他字符中都包含一个 space(所以,当然,我试图用这个填充的组件数据无法显示任何内容)。当我查看文件时,这是我看到的内容类型:
{ \ r t f 1 \ d e f f 0 { \ f o n t t b l { \ f 0 C a l i b r i ; } { \ f 1 A r i a l U n i c o d e M S ; } { \ f 2 B r i t a n n i c B o l d ; } } { \ c o l
我想坚持将 txt 变量存储为 UnicodeString
,因为实际项目有一个 class 来计算该字符串,但是有什么解决这个问题的想法吗?我意识到我可能会做一些耗时的事情,比如遍历并消除所有其他字符,但我想要一些有效的解决方案。
RTF 是一种 7 位 ASCII 格式,因此您根本不应将其视为 UTF-16。正确的解决方案是简单地将 UnicodeString
更改为 AnsiString
:
AnsiString txt = ...;
"extra spaces" 是由于在 UTF-16 中将 7 位 ASCII 字符扩展为 16 位值时添加了 0x00
个字节。
此外,您甚至没有将 UnicodeString
正确写入 TMemoryStream
。由于 WriteBuffer()
处理原始字节,而不是字符串字符,因此您需要将 txt.Length()
乘以 sizeof(System::WideChar)
以获得正确的字节数:
UnicodeString txt = ...;
...
AStream->WriteBuffer(txt.c_str(), txt.Length() * sizeof(WideChar));
如果改为AnsiString
,则不需要乘法,因为sizeof(AnsiChar)
是1。
但是,如果您坚持使用 UnicodeString
,那么至少要使用 TStringStream
,这样您就可以为其指定字节编码:
UnicodeString txt = ...;
TStringStream *AStream = new TStringStream(txt, TEncoding::ASCII);
...
此外,由于流是使用 new
创建的,您应该将 AStream->Free();
更改为 delete AStream;
。切勿在 C++ 中直接调用 TObject::Free()
,这是一个 Delphi 习惯用法。释放使用 new
分配的内容的 C++ 方法是 delete
。它将按预期调用 TObject
析构函数,就像 TObject::Free()
一样。
我试图用计算出的 RTF 文件的字符串填充 DevExpress VCL TdxRichEditControl
,而没有花时间保存文件。所以,这是一个演示项目:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
UnicodeString txt = "{\rtf1\deff0{\fonttbl{\f0 Calibri;}{\f1 Arial Unicode MS;}{\f2 Britannic Bold;}}{\colortbl ;\red0\green0\blue255 ;\red255\green0\blue0 ;}{\*\defchp \fs22}{\*\defpap \sl275\slmult1\sa200}{\stylesheet {\ql\sl275\slmult1\sa200\fs22 Normal;}{\*\cs1\fs22 Default Paragraph Font;}{\*\cs2\sbasedon1\fs22 Line Number;}{\*\cs3\ul\fs22\cf1 Hyperlink;}{\*\ts4\tsrowd\fs22\ql\sl275\slmult1\sa200\tscellpaddfl3\tscellpaddl108\tscellpaddfb3\tscellpaddfr3\tscellpaddr108\tscellpaddft3\tsvertalt\cltxlrtb Normal Table;}{\*\ts5\tsrowd\sbasedon4\fs22\ql\sl275\slmult1\sa200\trbrdrt\brdrs\brdrw10\trbrdrl\brdrs\brdrw10\trbrdrb\brdrs\brdrw10\trbrdrr\brdrs\brdrw10\trbrdrh\brdrs\brdrw10\trbrdrv\brdrs\brdrw10\tscellpaddfl3\tscellpaddl108\tscellpaddfr3\tscellpaddr108\tsvertalt\cltxlrtb Table Simple 1;}}{\*\listoverridetable}\nouicompat\splytwnine\htmautsp\sectd\pard\plain\ql\sl275\slmult1\sa200{\f1\fs28\cf1 This is in blue }{\b\i\f2\fs40\cf2 Red bold}\b\i\fs22\cf2\par}";
TMemoryStream *AStream = new TMemoryStream();
AStream->WriteBuffer(txt.c_str(), txt.Length());
AStream->Position = 0;
AStream->SaveToFile("C:/Trash/Test.rtf");
AStream->Position = 0;
dxRichEditControl1->Document->InsertDocumentContent(dxRichEditControl1->Document->Range->Start, AStream, TdxRichEditDocumentFormat::Rtf);
AStream->Free();
}
我在这个演示中将它保存到一个文件中以查看出了什么问题,发现该文件在每个其他字符中都包含一个 space(所以,当然,我试图用这个填充的组件数据无法显示任何内容)。当我查看文件时,这是我看到的内容类型:
{ \ r t f 1 \ d e f f 0 { \ f o n t t b l { \ f 0 C a l i b r i ; } { \ f 1 A r i a l U n i c o d e M S ; } { \ f 2 B r i t a n n i c B o l d ; } } { \ c o l
我想坚持将 txt 变量存储为 UnicodeString
,因为实际项目有一个 class 来计算该字符串,但是有什么解决这个问题的想法吗?我意识到我可能会做一些耗时的事情,比如遍历并消除所有其他字符,但我想要一些有效的解决方案。
RTF 是一种 7 位 ASCII 格式,因此您根本不应将其视为 UTF-16。正确的解决方案是简单地将 UnicodeString
更改为 AnsiString
:
AnsiString txt = ...;
"extra spaces" 是由于在 UTF-16 中将 7 位 ASCII 字符扩展为 16 位值时添加了 0x00
个字节。
此外,您甚至没有将 UnicodeString
正确写入 TMemoryStream
。由于 WriteBuffer()
处理原始字节,而不是字符串字符,因此您需要将 txt.Length()
乘以 sizeof(System::WideChar)
以获得正确的字节数:
UnicodeString txt = ...;
...
AStream->WriteBuffer(txt.c_str(), txt.Length() * sizeof(WideChar));
如果改为AnsiString
,则不需要乘法,因为sizeof(AnsiChar)
是1。
但是,如果您坚持使用 UnicodeString
,那么至少要使用 TStringStream
,这样您就可以为其指定字节编码:
UnicodeString txt = ...;
TStringStream *AStream = new TStringStream(txt, TEncoding::ASCII);
...
此外,由于流是使用 new
创建的,您应该将 AStream->Free();
更改为 delete AStream;
。切勿在 C++ 中直接调用 TObject::Free()
,这是一个 Delphi 习惯用法。释放使用 new
分配的内容的 C++ 方法是 delete
。它将按预期调用 TObject
析构函数,就像 TObject::Free()
一样。