为什么在TStringStream加载二进制非文本文件时,TStringStream.DataString的使用会失败?
正如专家们所建议的,为什么在TStringStream加载二进制非文本文件时,TStringStream.DataString的使用会失败?,string,delphi,hex,delphi-xe,stringstream,String,Delphi,Hex,Delphi Xe,Stringstream,正如专家们所建议的,TStringStream.DataString不能用于检索TStringStream.LoadFromFile加载的非文本数据,因为TStringStream.GetDataString将调用TEncoding的编码方法,例如TMBCSEncoding,将调用TMBCSEncoding.GetChars,它依次调用TMBCSEncoding.UnicodeFromLocaleChars,最后调用Windows的MultiByteToWideChar 建议使用T字节作为数据
TStringStream.DataString
不能用于检索TStringStream.LoadFromFile
加载的非文本数据,因为TStringStream.GetDataString
将调用TEncoding
的编码方法,例如TMBCSEncoding
,将调用TMBCSEncoding.GetChars
,它依次调用TMBCSEncoding.UnicodeFromLocaleChars
,最后调用Windows
的MultiByteToWideChar
建议使用T字节作为数据缓冲区/二进制存储器。(为此,建议T字节优先于AnsiString。)
可以从TStringStream.ReadBuffer
方法或TStringStream.bytes
属性检索bytes
。无论哪种方式,都应考虑TStream.Size
====================================================
我试图使用TStringStream
及其DataString
进行base64编码/解码。尼尔斯·哈克的回答或回答似乎表明了这一点
TMainForm.QuestionOfString_StringStream
(第2至第7项)中使用TStringStream.DataString
,失败原因是信息已损坏(即与原始信息不同)。但是,ss_loaded_2.SaveToFile
(No.1)保存原始信息,表明TStringStream
是否在内部正确保存解码的非文本数据?您能否帮助评论一下数据字符串损坏的可能原因
Rob Kennedy
善意的回答中,他提到在存储base64解码的非文本数据时应避免string
或ansisting
,这非常有意义。但是,如tmaninform.QuestionOfString_NativeXML
所示,AnsiString
类型的DecString
包含正确解码的字节,因此可以对数据进行编码。这是否意味着Anistring可以完整保存解码的非文本数据
David Heffernan
和Rob Kennedy
对bytes/TBytes发表了善意的评论。但是,在tmaninform.QuestionOfString_NativeXML_bytes_1
中提取的bytes
与tmaninform.QuestionOfString_NativeXML_bytes_2
中的TStringStream
的字节不同。(从Base64编码/解码结果来看,TStringStream.Bytes
是错误的。这是令人困惑的,因为根据上面的段落,TStringStream
应该在内部包含完整的字节。)您能帮我解释一下可能的原因吗
例3到例7的失败并不奇怪。您的文件不是文本数据,因此将其存储在文本数据结构中必然会出现问题。每个测试都涉及到将数据从一种编码转换为另一种编码。由于您的数据最初没有编码为UTF-16文本,因此任何期望数据具有该编码的转换都将失败 示例2可能会失败,因为您有奇数个字节,并且您将其存储在一个字符串中,根据定义,该字符串包含偶数个字节。在某个地方,一个字节将被引入或删除,从而导致存储不同的数据 除非处理文本,否则不要使用
TStringStream
、string
或ansisting
。请尝试tByteStream
或TMemoryStream
可以随意将Base64编码的数据存储在字符串中。Base64是一种文本格式。但一旦你解码了它,它又是二进制的了,再也不能用文本数据结构了
您现在看到的结果与Nils Haeck建议的结果不同的原因是,Haeck是在2007年编写的,当时Delphi字符串还没有变成Unicode,RTL进行了任何自动代码页转换。您使用的是Delphi XE,其中
string
是UnicodeString您没有考虑到TStringStream
源于D2009+中的TMemoryStream
和TByteStream
,但在早期版本中直接源于TStream
TMemoryStream
分配内存的方式与代码预期的方式不同,TByteStream.Bytes
属性表示TMemoryStream
分配的整个内存块,但这并不意味着该内存的全部内容都填充了实际数据。代码需要忽略一些额外的填充
有关代码失败原因的更详细解释,请参见我的答案。重复创建同一对象而不释放对象看起来有问题。如果只创建一次每个对象并根据需要替换数据字符串和编码,会怎么样?不释放对象是有问题的。不确定这是否是你具体问题的根源。@Xichen-你的问题似乎在不断演变。在你得到你原来问题的答案的时候,考虑另一个问题。@塞尔塔克阿库兹:谢谢你的提醒!我只是尽量不去问那些可能会被警告和重复的相关问题。(尽管如此,我会记得不要对原始帖子做太多修改,以免影响答案。)@Sertac,问题最终还是在于为什么TStringStream
失败。只是需要更深入的调查。表面上的答案是代码页会产生干扰,但这种情况究竟发生在何处,因为仅仅加载和保存数据的行为是不会发生的
unit uMainForm;
interface
uses
CodeSiteLogging,
NativeXml, // v3.10
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TMainForm = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
procedure QuestionOfString_StringStream;
procedure QuestionOfString_NativeXML;
procedure QuestionOfString_NativeXML_Bytes_1;
procedure QuestionOfString_NativeXML_Bytes_2;
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
// http://stackoverflow.com/questions/773297/how-can-i-convert-tbytes-to-rawbytestring
function Convert(const Bytes: TBytes): RawByteString;
begin
SetLength(Result, Length(Bytes));
if Length(Bytes) > 0 then
begin
Move(Bytes[0], Result[1], Length(Bytes));
// SetCodePage(Result, CP_ACP, False);
end;
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
QuestionOfString_StringStream;
QuestionOfString_NativeXML;
QuestionOfString_NativeXML_Bytes_1;
QuestionOfString_NativeXML_Bytes_2;
end;
// http://www.delphigroups.info/2/3/321962.html
// http://borland.newsgroups.archived.at/public.delphi.graphics/200712/0712125679.html
procedure TMainForm.QuestionOfString_StringStream;
var
ss_loaded_2, ss_loaded_3: TStringStream;
dataStr: AnsiString;
hexOfDataStr: AnsiString;
begin
ss_loaded_2 := TStringStream.Create();
// load the file containing Base64-decoded sample data
ss_loaded_2.LoadFromFile('REF_DecodedSample');
// 1
ss_loaded_2.SaveToFile('REF_DecodedSample_1_SavedByStringStream');
// 2
ss_loaded_3 := TStringStream.Create(ss_loaded_2.DataString);
ss_loaded_3.SaveToFile('REF_DecodedSample_2_SavedByStringStream');
// 3
ss_loaded_3.Free;
ss_loaded_3 := TStringStream.Create(ss_loaded_2.DataString, TEncoding.ASCII);
ss_loaded_3.SaveToFile('REF_DecodedSample_3_SavedByStringStream');
// 4
ss_loaded_3.Free;
ss_loaded_3 := TStringStream.Create(ss_loaded_2.DataString, TEncoding.UTF8);
ss_loaded_3.SaveToFile('REF_DecodedSample_4_SavedByStringStream');
// 5
ss_loaded_3.Free;
ss_loaded_3 := TStringStream.Create(AnsiString(ss_loaded_2.DataString));
ss_loaded_3.SaveToFile('REF_DecodedSample_5_SavedByStringStream');
// 6
ss_loaded_3.Free;
ss_loaded_3 := TStringStream.Create(UTF8String(ss_loaded_2.DataString));
ss_loaded_3.SaveToFile('REF_DecodedSample_6_SavedByStringStream');
// 7
dataStr := ss_loaded_2.DataString;
SetLength(hexOfDataStr, 2 * Length(dataStr));
BinToHex(@dataStr[1], PAnsiChar(@hexOfDataStr[1]), Length(dataStr));
CodeSite.Send(hexOfDataStr);
ss_loaded_2.Free;
ss_loaded_3.Free;
end;
// http://www.simdesign.nl/forum/viewtopic.php?f=2&t=1311
procedure TMainForm.QuestionOfString_NativeXML;
var
LEnc, LDec: integer;
EncStream: TMemoryStream;
DecStream: TMemoryStream;
EncString: AnsiString;
DecString: AnsiString;
begin
// encode and decode streams
EncStream := TMemoryStream.Create;
DecStream := TMemoryStream.Create;
try
// load BASE64-encoded data
EncStream.LoadFromFile('REF_EncodedSample');
LEnc := EncStream.Size;
SetLength(EncString, LEnc);
EncStream.Read(EncString[1], LEnc);
// decode BASE64-encoded data, after removing control chars
DecString := DecodeBase64(sdRemoveControlChars(EncString));
LDec := length(DecString);
DecStream.Write(DecString[1], LDec);
// save the decoded data
DecStream.SaveToFile('REF_DecodedSample_7_SavedByNativeXml');
// EncString := sdAddControlChars(EncodeBase64(DecString), #$0D#$0A);
EncString := EncodeBase64(DecString);
// clear and resave encode stream as a copy
EncStream.Clear;
EncStream.Write(EncString[1], Length(EncString));
EncStream.SaveToFile('REF_EncodedSampleCopy');
finally
EncStream.Free;
DecStream.Free;
end;
end;
procedure TMainForm.QuestionOfString_NativeXML_Bytes_1;
var
LEnc, LDec: integer;
EncStream: TMemoryStream;
DecStream: TMemoryStream;
EncString: AnsiString;
DecString: AnsiString;
DecBytes: TBytes;
begin
// encode and decode streams
EncStream := TMemoryStream.Create;
DecStream := TMemoryStream.Create;
try
// load BASE64-decoded data
DecStream.LoadFromFile('REF_DecodedSample');
LDec := DecStream.Size;
SetLength(DecBytes, LDec);
DecStream.Read(DecBytes[0], LDec);
EncString := EncodeBase64(Convert(DecBytes));
// clear and resave encode stream as a copy
EncStream.Write(EncString[1], Length(EncString));
EncStream.SaveToFile('REF_EncodedSampleCopy_Bytes_1');
finally
EncStream.Free;
DecStream.Free;
end;
end;
procedure TMainForm.QuestionOfString_NativeXML_Bytes_2;
var
LEnc, LDec: integer;
EncStream: TMemoryStream;
DecStream: TStringStream;
EncString: AnsiString;
DecString: AnsiString;
DecBytes: TBytes;
begin
// encode and decode streams
EncStream := TMemoryStream.Create;
DecStream := TStringStream.Create;
try
// load BASE64-decoded data
DecStream.LoadFromFile('REF_DecodedSample');
DecBytes := DecStream.Bytes;
EncString := EncodeBase64(Convert(DecBytes));
// clear and resave encode stream as a copy
EncStream.Write(EncString[1], Length(EncString));
EncStream.SaveToFile('REF_EncodedSampleCopy_Bytes_2');
finally
EncStream.Free;
DecStream.Free;
end;
end;
end.