Delphi 11读取TIdHTTP响应流转字符串报错问题咨询
Delphi 11中ZLib解压后响应流转String乱码问题解决方法
问题背景
已解决Delphi 11升级Indy 10后TIdHTTP发送数据的空格问题,当前遇到接收端问题:ZLib解压后的响应流转换为string时出现乱码,该逻辑在Delphi 6中可正常运行。
相关请求代码:
// sUrl - DSOAP Url // streamRequest - Request Stream and it will send as compressed data. // streamResponse - TStream of the response of DSOAP and it will receive as compressed. IdHttp.Post(sUrl, streamRequest, streamResponse)
原转换字符串代码:
var xml: PChar; sXML: string; iLength: string; // 类型定义错误 streamResponse: TStream; // 已通过ZLib解压 begin iLength := streamResponse.Seek(0, 2); xml = strAlloc(iLength+1); FillChar(xml^, iLength+1, #0); streamResponse.Seek(0, 0); streamResponse.Read(xml^, iLength); sXML := strPas( xml ); // 此处出现乱码 strDispose(xml); end;
问题分析
- 类型错误:
iLength被定义为string,但TStream.Seek返回的是Int64类型,类型不匹配会导致长度计算错误,进而引发内存操作异常。 - 编码不兼容:Delphi 11的
string是UnicodeString(宽字符),而strAlloc/strPas是基于Ansi字符的旧API,直接将字节流转为宽字符时,会默认使用系统本地编码,若响应流是UTF-8等编码,必然出现乱码。 - 内存操作不安全:手动分配PChar内存容易出现越界或释放问题,在Unicode环境下这类操作的风险被放大。
解决方法
方法1:使用TStreamReader读取(推荐)
利用TStreamReader直接读取流,指定响应的正确编码(SOAP服务通常返回UTF-8编码):
var sXML: string; streamResponse: TStream; // 已解压的响应流 begin streamResponse.Seek(0, soBeginning); with TStreamReader.Create(streamResponse, TEncoding.UTF8) do try sXML := ReadToEnd; finally Free; end; end;
方法2:读取字节数组后转换编码
先将流读取到字节数组,再通过TEncoding转换为UnicodeString:
var sXML: string; Bytes: TBytes; streamResponse: TStream; // 已解压的响应流 iLength: Int64; begin iLength := streamResponse.Seek(0, soEnd); streamResponse.Seek(0, soBeginning); SetLength(Bytes, iLength); streamResponse.ReadBuffer(Bytes[0], iLength); sXML := TEncoding.UTF8.GetString(Bytes); // 若服务返回其他编码,替换为对应编码,如TEncoding.GetEncoding('GBK') end;
关键注意点
- 务必确认响应流的实际编码:若SOAP服务返回的是GBK等非UTF-8编码,需替换对应的
TEncoding类型。 - 放弃Ansi时代的字符API:在Delphi 2009及以后的Unicode版本中,优先使用
TStreamReader、TEncoding等Unicode兼容的类和方法。
内容的提问来源于stack exchange,提问作者sn_na_v
相关产品推荐
相关产品推荐

