【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;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值