zoukankan      html  css  js  c++  java
  • Delphi BASE64单元EncdDecd的修改

    Delphi BASE64单元EncdDecd的修改

    EncdDecd.pas两个函数声明:

    procedure EncodeStream(Input, Output: TStream);
    procedure DecodeStream(Input, Output: TStream);

    对于Output参数,如果是TMemoryStream,效率真是太糟糕了,测试发现,编码一个5M多的文件,要十几秒钟!

    但如果是TStringStream,只要0.2~0.3秒!

    WHY?

    因为TMemoryStream在不断地调用Write方法,不断地向Windows要求分配内存!从而导致性能下降!而TStringStream和TFileStream则没有这个问题。

    怎么办?

    可以一次性给TMemoryStream分配好内存空间。假设编码前的字节数为X,那麽编码后的字节数为 (X + 2) div 3 * 4

    假设解码前的字节数是X,那麽解码后的字节数约为 (X + 3) div 4 * 3

    关于回车换行符的修改,找到下面这段代码:

    if K > 75 then     
       begin
        BufPtr[0] := #$0D; // 回车
        BufPtr[1] := #$0A; // 换行
        Inc(BufPtr, 2);
        K := 0;
       end; 

    每隔76个字符,就强制回车换行。将其注释掉, 因为这其实是没什么用。将修改的单元另存为EncdDecdEx,以后就使用它了。

    在编码/解码前对Output参数的TMemoryStream事先设置缓冲区大小,避免分多次向WINDOWS申请内存分配:

    uses
      encddecdEx; 
     var
      Input,Output:TMemoryStream;
     begin
      Input:=TMemoryStream.Create;
      try
       Input.LoadFromFile('c:aaa.txt');
       Output:=TMemoryStream.Create;
       try
        Output.Size:=(Input.Size + 2) div 3 * 4;
        EncodeStream(Input,Output);
       finally
        Output.Free;
       end;
      finally
       Input.Free;
      end;
     end;
    

      对D7自带的BASE64单元改造后的源码:

    /// <author>cxg 2020-2-29</author>
    {
    在编码/解码前对Output参数的TMemoryStream事先设置缓冲区大小,避免分多次向WINDOWS申请内存分配
    uses
      encddecdEx; 
     var
      Input,Output:TMemoryStream;
     begin
      Input:=TMemoryStream.Create;
      try
       Input.LoadFromFile('c:aaa.txt');
       Output:=TMemoryStream.Create;
       try
        Output.Size:=(Input.Size + 2) div 3 * 4;
        EncodeStream(Input,Output);
       finally
        Output.Free;
       end;
      finally
       Input.Free;
      end;
     end;
    }
    unit base64;
    
    interface
    
    uses Classes;
    
    procedure EncodeStream(Input, Output: TStream);
    procedure DecodeStream(Input, Output: TStream);
    function  EncodeString(const Input: string): string;
    function  DecodeString(const Input: string): string;
    
    implementation
    
    const
      EncodeTable: array[0..63] of Char =
        'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
        'abcdefghijklmnopqrstuvwxyz' +
        '0123456789+/';
    
      DecodeTable: array[#0..#127] of Integer = (
        Byte('='), 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
        64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
        64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
        64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
        64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
        41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64);
    
    type
      PPacket = ^TPacket;
      TPacket = packed record
        case Integer of
          0: (b0, b1, b2, b3: Byte);
          1: (i: Integer);
          2: (a: array[0..3] of Byte);
          3: (c: array[0..3] of Char);
      end;
    
    procedure EncodePacket(const Packet: TPacket; NumChars: Integer; OutBuf: PChar);
    begin
      OutBuf[0] := EnCodeTable[Packet.a[0] shr 2];
      OutBuf[1] := EnCodeTable[((Packet.a[0] shl 4) or (Packet.a[1] shr 4)) and $0000003f];
      if NumChars < 2 then
        OutBuf[2] := '='
      else OutBuf[2] := EnCodeTable[((Packet.a[1] shl 2) or (Packet.a[2] shr 6)) and $0000003f];
      if NumChars < 3 then
        OutBuf[3] := '='
      else OutBuf[3] := EnCodeTable[Packet.a[2] and $0000003f];
    end;
    
    function DecodePacket(InBuf: PChar; var nChars: Integer): TPacket;
    begin
      Result.a[0] := (DecodeTable[InBuf[0]] shl 2) or
        (DecodeTable[InBuf[1]] shr 4);
      NChars := 1;
      if InBuf[2] <> '=' then
      begin
        Inc(NChars);
        Result.a[1] := Byte((DecodeTable[InBuf[1]] shl 4) or (DecodeTable[InBuf[2]] shr 2));
      end;
      if InBuf[3] <> '=' then
      begin
        Inc(NChars);
        Result.a[2] := Byte((DecodeTable[InBuf[2]] shl 6) or DecodeTable[InBuf[3]]);
      end;
    end;
    
    procedure EncodeStream(Input, Output: TStream);
    type
      PInteger = ^Integer;
    var
      InBuf: array[0..509] of Byte;
      OutBuf: array[0..1023] of Char;
      BufPtr: PChar;
      I, J, K, BytesRead: Integer;
      Packet: TPacket;
    begin
      K := 0;
      repeat
        BytesRead := Input.Read(InBuf, SizeOf(InBuf));
        I := 0;
        BufPtr := OutBuf;
        while I < BytesRead do
        begin
          if BytesRead - I < 3 then
            J := BytesRead - I
          else J := 3;
          Packet.i := 0;
          Packet.b0 := InBuf[I];
          if J > 1 then
            Packet.b1 := InBuf[I + 1];
          if J > 2 then
            Packet.b2 := InBuf[I + 2];
          EncodePacket(Packet, J, BufPtr);
          Inc(I, 3);
          Inc(BufPtr, 4);
          Inc(K, 4);
    //      if K > 75 then    //rem by cxg 每隔76个字符,就强制回车换行。将其注释掉
    //      begin
    //        BufPtr[0] := #$0D;
    //        BufPtr[1] := #$0A;
    //        Inc(BufPtr, 2);
    //        K := 0;
    //      end;
        end;
        Output.Write(Outbuf, BufPtr - PChar(@OutBuf));
      until BytesRead = 0;
    end;
    
    procedure DecodeStream(Input, Output: TStream);
    var
      InBuf: array[0..75] of Char;
      OutBuf: array[0..60] of Byte;
      InBufPtr, OutBufPtr: PChar;
      I, J, K, BytesRead: Integer;
      Packet: TPacket;
    
      procedure SkipWhite;
      var
        C: Char;
        NumRead: Integer;
      begin
        while True do
        begin
          NumRead := Input.Read(C, 1);
          if NumRead = 1 then
          begin
            if C in ['0'..'9','A'..'Z','a'..'z','+','/','='] then
            begin
              Input.Position := Input.Position - 1;
              Break;
            end;
          end else Break;
        end;
      end;
    
      function ReadInput: Integer;
      var
        WhiteFound, EndReached : Boolean;
        CntRead, Idx, IdxEnd: Integer;
      begin
        IdxEnd:= 0;
        repeat
          WhiteFound := False;
          CntRead := Input.Read(InBuf[IdxEnd], (SizeOf(InBuf)-IdxEnd));
          EndReached := CntRead < (SizeOf(InBuf)-IdxEnd);
          Idx := IdxEnd;
          IdxEnd := CntRead + IdxEnd;
          while (Idx < IdxEnd) do
          begin
            if not (InBuf[Idx] in ['0'..'9','A'..'Z','a'..'z','+','/','=']) then
            begin
              Dec(IdxEnd);
              if Idx < IdxEnd then
                Move(InBuf[Idx+1], InBuf[Idx], IdxEnd-Idx);
              WhiteFound := True;
            end
            else
              Inc(Idx);
          end;
        until (not WhiteFound) or (EndReached);
        Result := IdxEnd;
      end;
    
    begin
      repeat
        SkipWhite;
        {
        BytesRead := Input.Read(InBuf, SizeOf(InBuf));
        }
        BytesRead := ReadInput;
        InBufPtr := InBuf;
        OutBufPtr := @OutBuf;
        I := 0;
        while I < BytesRead do
        begin
          Packet := DecodePacket(InBufPtr, J);
          K := 0;
          while J > 0 do
          begin
            OutBufPtr^ := Char(Packet.a[K]);
            Inc(OutBufPtr);
            Dec(J);
            Inc(K);
          end;
          Inc(InBufPtr, 4);
          Inc(I, 4);
        end;
        Output.Write(OutBuf, OutBufPtr - PChar(@OutBuf));
      until BytesRead = 0;
    end;
    
    function EncodeString(const Input: string): string;
    
    var
      InStr, OutStr: TStringStream;
    begin
      InStr := TStringStream.Create(Input);
      try
        OutStr := TStringStream.Create('');
        try
          EncodeStream(InStr, OutStr);
          Result := OutStr.DataString;
        finally
          OutStr.Free;
        end;
      finally
        InStr.Free;
      end;
    end;
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    function DecodeString(const Input: string): string;
    
    var
      InStr, OutStr: TStringStream;
    begin
      InStr := TStringStream.Create(Input);
      try
        OutStr := TStringStream.Create('');
        try
          DecodeStream(InStr, OutStr);
          Result := OutStr.DataString;
        finally
          OutStr.Free;
        end;
      finally
        InStr.Free;
      end;
    end;
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    end.
    

      

  • 相关阅读:
    P4342 [IOI1998]Polygon
    P1194 买礼物
    P1363 幻想迷宫
    Installing Wine 1.5: configure: error: Cannot build a 32-bit program, you need to install 32-bit development libraries(转载)
    Linux系统调用之open(), close() (转载)
    undefined reference to 'pthread_create'问题解决(转载)
    linux中的C里面使用pthread_mutex_t锁(转载)
    #if、#ifdef、#if defined之间的区别(转载)
    linux下解压tgz文件(转载)
    linux修改用户主目录的方法 (转载)
  • 原文地址:https://www.cnblogs.com/hnxxcxg/p/11100160.html
Copyright © 2011-2022 走看看