【Delphi】解决的TIdFtp组件在使用压缩方式下载有时会报错的问题 [更新:Delphi 10.3又有新Bug]

本人在使用Delphi TIdFtp进行压缩方式下载时,发现有时会报一个EIdReplyRFCError类型的错误,错误信息为Data connection closed abnormally。经分析发现是由于IdCompressorZLib单元的procedure TIdCompressorZLib.InternalDecompressStream处理不当造成的。估计全部Delphi版本自带的TIdFtp估计都有此问题。       本人在使用Delphi TIdFtp进行压缩方式下载时,发现有时会报一个EIdReplyRFCError类型的错误,错误信息为Data connection closed abnormally。经分析发现是由于IdCompressorZLib单元的procedure TIdCompressorZLib.InternalDecompressStream处理不当造成的。估计全部Delphi版本自带的TIdFtp估计都有此问题。解决方法如下:

在procedure TIdCompressorZLib.InternalDecompressStream中找到
       DCheck(inflate(LZstream,Z_NO_FLUSH)); //把这行改为下命两行:
       zresult := inflate(LZstream, Z_NO_FLUSH);
       if zresult <> Z_BUF_ERROR then DCheck(zresult); //Z_BUF_ERROR属于正常情况
另外,从Delphi 10.3 Rio开始,由于Delphi自带的zlib版本更新,需要做如下改动:
procedure InternalDecompressStream(LZstream: TZStreamRec; AIOHandler : TIdIOHandler;
      AOutStream: TStream);
改为
procedure InternalDecompressStream(var LZstream: TZStreamRec; AIOHandler : TIdIOHandler;
      AOutStream: TStream);

也就是把LZstream从传值改为传地址

 

----------------------------------------------------------------------------------------------------------------------------
更详细的解决方法请参考下面的内容(以Delphi 11.2为例):

procedure TIdCompressorZLib.InternalDecompressStream(
  var LZstream: TZStreamRec; AIOHandler: TIdIOHandler; AOutStream: TStream);
var
  zresult  : Integer;
  outBuffer: Array [0..bufferSize-1] of TIdAnsiChar;
  inSize   : Integer;
  outSize  : Integer;
  LBuf : TIdBytes;

  function RawReadFromIOHandler(ABuffer : TIdBytes; AOIHandler : TIdIOHandler; AMax : Integer) : Integer;
  begin
    try
      AIOHandler.ReadBytes(ABuffer, AMax, False);
    except
      on E: Exception do begin
        AMax := IndyMin(AMax, AIOHandler.InputBuffer.Size);
        AIOHandler.InputBuffer.ExtractToBytes(ABuffer, AMax, False);
        if not (E is EIdConnClosedGracefully) then begin
          raise;
        end;
      end;
    end;
    TIdAntiFreezeBase.DoProcess;
    Result := AMax;
  end;

begin
  SetLength(LBuf, bufferSize);
  repeat
    inSize := RawReadFromIOHandler(LBuf, AIOHandler, bufferSize);
    if inSize < 1 then begin
      Break;
    end;

    LZstream.next_in := PIdAnsiChar(@LBuf[0]);
    LZstream.avail_in := inSize;

    repeat
      LZstream.next_out := @outBuffer[0];
      LZstream.avail_out := bufferSize;

    //DCheck(inflate(LZstream,Z_NO_FLUSH)); //<---此行处理不当,改为下面两行: <-------------------------------------
      zresult := inflate(LZstream, Z_NO_FLUSH);
      if zresult <> Z_BUF_ERROR then DCheck(zresult); //Z_BUF_ERROR属于正常情况
    //--------------------------------------------------------------------------

      outSize := bufferSize - LZstream.avail_out;
      AOutStream.Write(outBuffer, outSize);

    until (LZstream.avail_in = 0) and (LZstream.avail_out > 0);
  until False;
  repeat
    LZstream.next_out := @outBuffer[0];
    LZstream.avail_out := bufferSize;

    zresult := inflate(LZstream, Z_FINISH);
    if zresult <> Z_BUF_ERROR then
    begin
      zresult := DCheck(zresult);
    end;
    outSize := bufferSize - LZstream.avail_out;
    AOutStream.Write(outBuffer, outSize);

  until ((zresult = Z_STREAM_END) and (LZstream.avail_out > 0)) or (zresult = Z_BUF_ERROR);

  DCheck(inflateEnd(LZstream));
end;
上一篇: 【Delphi】解决XE3及以上版本中的ClientDataSet的长中文字段名出现乱码的问题【此问题从Delphi 10.3.3开始已解决】
下一篇: 【RISC-V】使用Arduino IDE开发环境编写的Hifive1开发板演示程序(Demo)。
BlueStorm
博客等级 码龄25年 74粉丝 38原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值