Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么在TStringStream加载二进制非文本文件时,TStringStream.DataString的使用会失败?_String_Delphi_Hex_Delphi Xe_Stringstream - Fatal编程技术网

为什么在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
    应该在内部包含完整的字节。)您能帮我解释一下可能的原因吗

  • 非常感谢你的帮助

    PS:可以从SkyDrive下载示例文件:。(Zlib压缩图像文件)

    PS:DelphiXE,Windows7。(Delphi 7中的TStringStream似乎没有LoadFromFile或SaveToFile。)

    示例代码
    例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.