目标多字节代码页中是否存在Unicode字符的映射? (德尔福XE6)

时间:2014-07-09 11:21:09

标签: delphi delphi-xe6

以下代码适用于Win32,无论如何,如果在Android或iOS上运行,它都是异常的。 例外情况是:“目标多字节代码页中不存在Unicode字符的映射”

function Form1.ZDecompressString(aText: String): String;
var
  strInput,
  strOutput : TStringStream;
  Unzipper  : TZDecompressionStream;
begin

   Result    := '';
   strInput  := TStringStream.Create( aText );
   strOutput := TStringStream.Create;

   try

      Unzipper := TZDecompressionStream.Create( strInput );

      try
         strOutput.CopyFrom( Unzipper, Unzipper.Size );
      finally
         Unzipper.Free;
      end;

      Result := strOutput.DataString;

   finally
      strInput.Free;
      strOutput.Free;
   end;
end;

procedure Form1.getUsers;
var
   XMLRqst     : String;
   XMLResponse : TStringStream;
   XMLRequest  : TStringStream;
   idHTTP      : TIdHTTP;

   s : String;
begin

   XMLRqst     := UTF8ToString( '<root company="belvew"/>' );
   XMLRequest  := TStringStream.Create( XMLRqst, TEncoding.UTF8 );
   XMLResponse := TStringStream.Create( '' );

   try
      try
         idHTTP                 := TIdHTTP.Create( Self );
         idHTTP.CookieManager   := idCookieManager;
         idHTTP.ReadTimeout     := 60000;{ IdTimeoutInfinite; }
         idHTTP.ConnectTimeout  := 60000;
         idHTTP.HandleRedirects := True;

         XMLResponse.Position   := 0;
         XMLRequest.Position    := 0;

         idHTTP.Post( 'http://localhost/API/getUsers.aspx', XMLRequest, XMLResponse );
         idHTTP.Disconnect;

         unique_id := ZDecompressString( XMLResponse.DataString );

         XMLRequest.Free;
         XMLResponse.Free;

      except
         on E : Exception do
        begin
            ShowMessage( 'exception : '#13 + E.Message );
        end;
      end;

   finally
      idHTTP.Free;
   end;

end;

procedure Form1.onCreate( Sender : TObject );
begin
   getUsers;
end;
  • 为什么代码在Android或iOS下不起作用?

2 个答案:

答案 0 :(得分:7)

我会说你需要抛弃这些代码并重新开始。像我遇到的所有压缩算法一样,zlib不对文本进行操作。它在字节数组上运行。回到Delphi字符串使用8位编码的日子里,人们用这样的字符串快速松散地播放,将它们视为字节数组。从那时起,压缩可以对字符串进行操作的误解已经持续。

您需要选择一个用于将文本转换为字节数组的编码。一个不错的选择是UTF-8。然后,如果要将压缩数据表示为文本,则需要使用类似base64的编码。

压缩过程如下:

  1. 将文本编码为UTF-8字节数组。
  2. 使用zlib压缩。
  3. 使用base64对压缩字节数组进行编码。
  4. 在相反的方向你会:

    1. 将base64文本解码为压缩字节数组。
    2. 使用zlib解压缩。
    3. 将UTF-8编码的字节数组解码为文本。
    4. 要使用TEncoding.UTF8对UTF-8进行编码/解码。您需要GetBytesGetString方法。对于base64编码/解码,您可能最好建议使用Indy库,因为您已经在使用它。


      根据评论,你已经解压缩到UTF-8编码的字节数组。在这种情况下,最后一步是写:

      text := TEncoding.UTF8.GetString(utf8byteArray);
      

答案 1 :(得分:5)

除了David所说的,你的代码使用了一些字节&lt; - &gt;字符串转换为其中一些使用了未指定的编码,所以你要受ANSI&lt; - &gt; Unicode转换的影响,这可能会丢失数据。

更重要的是,您所做的只是解压缩HTTP响应的原始二进制数据,但使用TStringStream来执行此操作。这本身就是错误的,因为压缩操作的是字节,而不是字符。但是,TIdHTTP还有内置支持,用于解压缩HTTP响应,如果响应的Content-Encoding标头为deflategzip 。在这种情况下,由于您没有填写TIdHTTP.Request.AcceptEncoding属性,因此不应该有HTTP级别的压缩。但是,让我们说(例如,有错误的服务器实现)。要启用该功能,您只需分配TIdHTTP.Compressor属性,然后让TIdHTTP在内部为您完成剩下的工作。这将大大简化您的代码,例如:

uses
  ..., IdCompressorZLib;

procedure Form1.getUsers;
var
  XMLRqst     : String;
  XMLRequest  : TStringStream;
  idHTTP      : TIdHTTP;
begin
  XMLRqst := '<root company="belvew"/>';

  try
    XMLRequest := TStringStream.Create( XMLRqst, TEncoding.UTF8 );
    try
      idHTTP := TIdHTTP.Create;
      try
        idHTTP.CookieManager   := idCookieManager;
        idHTTP.ReadTimeout     := 60000;{ IdTimeoutInfinite; }
        idHTTP.ConnectTimeout  := 60000;
        idHTTP.HandleRedirects := True;
        idHTTP.Compressor := TIdCompressorZLib.Create(idHTTP);

        unique_id := idHTTP.Post( 'http://localhost/API/getUsers.aspx', XMLRequest );
      finally
        idHTTP.Free;
      end;
    finally
      XMLRequest.Free;
    end;
  except
    on E : Exception do
    begin
      ShowMessage( 'exception : '#13 + E.Message );
    end;
  end;
end;