4
  1. 正如专家所建议的那样,TStringStream.DataString不能用于检索non-text由 加载的数据TStringStream.LoadFromFile,因为TStringStream.GetDataStringwill callTEncoding的编码方法,TMBCSEncoding例如,将调用TMBCSEncoding.GetCharswhich 依次调用TMBCSEncoding.UnicodeFromLocaleChars和 finallyWindowsMultiByteToWideChar

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

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

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

我正在尝试将TStringStreamDataString用于 base64 编码/解码目的。正如这里这里Nils Haeck的回复所表明的那样,这似乎是可能的。

  1. 使用TStringStream.DataStringin TMainForm.QuestionOfString_StringStream(No.2 到 No.7) 失败的原因是信息已损坏(即与原始信息不同)。但是,ss_loaded_2.SaveToFile(No.1)保存了原始信息,表明TStringStream内部是否正确保存了解码的非文本数据?您能帮忙评论一下 DataString 损坏的可能原因吗?

  2. Rob Kennedy的友好回答中,他提到stringansistring应该避免存储 base64 解码的非文本数据,这很有意义。但是,如 中所示TMainForm.QuestionOfString_NativeXMLDecStringofAnsiString类型包含正确解码的字节,因此可以将数据编码回。这是否意味着 AnsiString 可以完整地保存解码的非文本数据?

  3. David Heffernan并对Rob Kennedy字节/TBytes 发表了友好的评论。但是,bytes提取的 inTMainForm.QuestionOfString_NativeXML_Bytes_1TStringStream's Bytesin不同TMainForm.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.
4

2 回答 2

9

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

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

除非您正在处理文本,否则不要使用TStringStream,stringAnsiString. 尝试TBytesStreamTMemoryStream代替。

随意将 Base64 编码的数据存储在字符串中。Base64 是一种文本格式。但是一旦你解码它,它又是二进制的,并且不再需要在文本数据结构中了。

您现在看到的结果与 Nils Haeck 建议的结果不同的原因是,Haeck 是在 2007 年编写的,当时 Delphi 字符串成为 Unicode 并且 RTL 进行了任何自动代码页转换。您正在使用 Delphi stringXE UnicodeString,.

于 2012-07-05T14:59:27.363 回答
3

您没有考虑从 D2009+TStringStream派生TMemoryStreamTByteStream在 D2009+ 中派生,而是直接从TStream早期版本派生而来。 TMemoryStream分配内存的方式与您的代码预期的不同,并且该TByteStream.Bytes属性表示TMemoryStream分配的整个内存块,但这并不意味着该内存的全部内容都填充了实际数据。您的代码需要忽略一些额外的填充。

有关您的代码失败原因的更详细说明,请参阅我对您的其他问题的回答。

于 2012-07-05T22:56:15.547 回答