【问题标题】:No mapping for the Unicode character exists in the target multi-byte code page ? (Delphi XE6)目标多字节代码页中不存在 Unicode 字符的映射? (德尔福 XE6)
【发布时间】:2014-08-30 09:35:47
【问题描述】:

以下代码适用于 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 下不起作用?

【问题讨论】:

    标签: delphi delphi-xe6


    【解决方案1】:

    我会说你需要扔掉这段代码并重新开始。像我遇到的所有压缩算法一样,zlib 不对文本进行操作。它对字节数组进行操作。早在 Delphi 字符串使用 8 位编码的日子里,人们对这些字符串玩得又快又松,把它们当作字节数组对待。从那时起,压缩可以在弦上运行的误解一直存在。

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

    压缩过程如下:

    1. 将文本编码为 UTF-8 字节数组。
    2. 用 zlib 压缩。
    3. 使用 base64 对压缩字节数组进行编码。

    你会在相反的方向:

    1. 将 base64 文本解码为压缩字节数组。
    2. 用 zlib 解压。
    3. 将 UTF-8 编码的字节数组解码为文本。

    要编码/解码 UTF-8,请使用 TEncoding.UTF8GetBytesGetString 方法是您所需要的。对于 base64 编码/解码,最好建议您使用 Indy 库,因为您已经在使用它了。


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

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

    【讨论】:

    • 我现在明白了这个问题,但最糟糕的是服务器实际上是专有的,我实际上无法改变它的工作方式。如果服务器只是用 zlib 压缩字符串,我可以使用一些解决方法吗? (目前它确实适用于 Java 和 ActionScript3 客户端)。
    • 符合服务器期望可能并不难。但我认为你需要弄清楚确切的步骤是什么。涉及哪些编码?
    • 结果字符串(解压后)为UTF8编码。
    • 那我猜你只需要text := TEncoding.UTF8.GetString(utf8byteArray);就完成了
    【解决方案2】:

    除了 David 所说的之外,您的代码对其中一些使用未指定的编码进行了太多字节字符串转换,因此您会受到 ANSIUnicode 转换的影响,这可能会丢失数据。

    更重要的是,您真正要做的只是解压缩 HTTP 响应的原始二进制数据,但使用 TStringStream 来执行此操作。这本身就是错误的,因为压缩是针对字节而不是字符进行的。而且,TIdHTTP 具有内置支持,用于解压缩 HTTP 响应,如果响应具有 deflategzipContent-Encoding 标头。在这种情况下,由于您没有填写 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;
    

    【讨论】:

    • 非常感谢 Remy 的便条! :)
    猜你喜欢
    • 2014-11-21
    • 2017-03-21
    • 2013-08-14
    • 2014-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-13
    相关资源
    最近更新 更多