加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

当TStringStream加载二进制非文本文件时,为什么TStringStream.Da

发布时间:2020-12-15 09:41:48 所属栏目:大数据 来源:网络整理
导读:正如专家建议的那样,TStringStream.DataString不能用于检索由TStringStream.LoadFromFile加载的非文本数据,因为TStringStream.GetDataString将调用TEncoding的编码方法,例如,以TMBCSEncoding为例,将调用TMBCSEncoding.GetChars反过来调用TMBCSEncoding.Unico
>正如专家建议的那样,TStringStream.DataString不能用于检索由TStringStream.LoadFromFile加载的非文本数据,因为TStringStream.GetDataString将调用TEncoding的编码方法,例如,以TMBCSEncoding为例,将调用TMBCSEncoding.GetChars反过来调用TMBCSEncoding.UnicodeFromLocaleChars,最后是 Windows的MultiByteToWideChar.
>建议将TBytes用作数据缓冲区/二进制存储. (为此,建议使用TBytes而不是AnsiString.)
>可以从TStringStream.ReadBuffer方法或TStringStream.Bytes属性中检索字节.无论哪种方式,都应该考虑TStream.Size.

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

我试图使用TStringStream及其DataString进行base64编码/解码.似乎有可能如Nils Haeck的回复here或here所示.

>在TMainForm.QuestionOfString_StringStream(No.2至No.7)中使用TStringStream.DataString失败,因为信息已损坏(即,与原始信息不同).但是,ss_loaded_2.SaveToFile(No.1)保存原始信息,表明TStringStream在内部正确保存解码的非文本数据?你能帮忙评论一下DataString损坏的可能原因吗?
>在Rob Kennedy的回答中,他提到字符串或ansistring应该避免存储base64解码的非文本数据,这很有意义.但是,如TMainForm.QuestionOfString_NativeXML所示,AnsiStringtype的DecString包含正确的解码字节,以便可以对数据进行编码.这是否意味着AnsiString可以保存已解码的非文本数据?
> David Heffernan和Rob Kennedy对字节/ TBytes表示赞赏.但是,在TMainForm.QuestionOfString_NativeXML_Bytes_1中提取的字节与TMainForm.QuestionOfString_NativeXML_Bytes_2中的TStringStream的字节不同. (从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}    

// https://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.

解决方法

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

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

除非您正在处理文本,否则请不要使用TStringStream,string或AnsiString.请尝试使用TBytesStream或TMemoryStream.

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

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读