当TStringStream加载二进制非文本文件时,为什么TStringStream.DataString的使用失败?

SOU*_*ser 4 delphi string hex stringstream delphi-xe

  1. 正如专家已经建议好心,TStringStream.DataString不能用于检索non-text由加载的数据TStringStream.LoadFromFile,因为TStringStream.GetDataString会叫TEncoding的编码方法,其中,采取TMBCSEncoding例如,将调用TMBCSEncoding.GetChars这反过来又来电TMBCSEncoding.UnicodeFromLocaleChars,最后WindowsMultiByteToWideChar.

  2. 建议将TBytes用作数据缓冲区/二进制存储.(为此,建议使用TBytes而不是AnsiString.)

  3. bytes可以从被检索TStringStream.ReadBuffer的方法或TStringStream.Bytes属性.无论哪种方式,TStream.Size都应该考虑.

================================================== ==

我正在尝试使用TStringStream它并DataString用于base64编码/解码目的.似乎有可能如此此处Nils Haeck的回复所示.

  1. 使用TStringStream.DataStringTMainForm.QuestionOfString_StringStream(第2号至7号)失败,该信息已损坏(即不一样的原始信息).但是,ss_loaded_2.SaveToFile(No.1)保存原始信息,表示TStringStream是否在内部正确保存解码的非文本数据?你能帮忙评论一下DataString损坏的可能原因吗?

  2. Rob Kennedy他的答复中,他提到stringansistring应该避免存储base64解码的非文本数据,这很有意义.然而,如图中TMainForm.QuestionOfString_NativeXML,所述DecStringAnsiString类型包含所以正确的数据可以被编码回经解码的字节.这是否意味着AnsiString可以保存已解码的非文本数据?

  3. David Heffernan并且Rob Kennedy好好评论了字节/ TBytes.然而,bytes提取的TMainForm.QuestionOfString_NativeXML_Bytes_1,从不同TStringStreamBytesTMainForm.QuestionOfString_NativeXML_Bytes_2.(从Base64编码/解码结果来看,这TStringStream.Bytes是错误的.它是令人困惑的,因为根据上面的段落,TStringStream内部应该包含完整的字节?)你能否帮助评论可能的原因?

非常感谢您的帮助!

PS:可以从SkyDrive下载示例文件:REF_EncodedSample和REF_DecodedSample.(Zlib压缩的图像文件.).

PS:Delphi XE,Windows 7.(似乎在Delphi 7中的TStringStream没有LoadFromFile或SaveToFile.)

示例代码

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.
Run Code Online (Sandbox Code Playgroud)

Rob*_*edy 9

示例3到7失败并不奇怪.您的文件不是文本数据,因此将其存储在文本数据结构中肯定会出现问题.每个测试都涉及将数据从一种编码转换为另一种编码.由于您的数据未编码为UTF-16文本,因此任何期望数据具有该编码的转换都将失败.

示例2可能会失败,因为您有一个奇数个字节,并且您将它存储在一个字符串中,根据定义,该字符串包含偶数个字节.在某处,将引入或删除一个字节,从而导致存储不同的数据.

除非你在处理文本,不使用TStringStream,stringAnsiString.尝试TBytesStreamTMemoryStream改为.

随意将Base64编码的数据存储在字符串中.Base64是一种文本格式.但是一旦你解码它,它再次成为二进制文件,并且再也没有业务在文本数据结构中了.

你现在看到Nils Haeck建议你应该期待的不同结果的原因是Haeck在2007年写作,之后Delphi字符串变为Unicode并且RTL进行了任何自动代码页转换.您使用德尔福XE,这里stringUnicodeString.