张志学 發表於 2019-6-27 22:55:00

Delphi BASE64单元EncdDecd的修改

<p>Delphi BASE64单元EncdDecd的修改</p>
<p>EncdDecd.pas两个函数声明:</p>
<p>procedure EncodeStream(Input, Output: TStream);<br>procedure DecodeStream(Input, Output: TStream);</p>
<p>对于Output参数,如果是TMemoryStream,效率真是太糟糕了,测试发现,编码一个5M多的文件,要十几秒钟!</p>
<p>但如果是TStringStream,只要0.2~0.3秒! </p>
<p>WHY?</p>
<p>因为TMemoryStream在不断地调用Write方法,不断地向Windows要求分配内存!从而导致性能下降!而TStringStream和TFileStream则没有这个问题。</p>
<p>怎么办?</p>
<p>可以一次性给TMemoryStream分配好内存空间。假设编码前的字节数为X,那麽编码后的字节数为 (X + 2) div 3 * 4</p>
<p>假设解码前的字节数是X,那麽解码后的字节数约为 (X + 3) div 4 * 3</p>
<p>关于回车换行符的修改,找到下面这段代码:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">if K &gt; 75 then     
   begin
    BufPtr := #$0D; // 回车
    BufPtr := #$0A; // 换行
    Inc(BufPtr, 2);
    K := 0;
   end; </pre>
</div>
<p>每隔76个字符,就强制回车换行。将其注释掉, 因为这其实是没什么用。将修改的单元另存为EncdDecdEx,以后就使用它了。</p>
<p>在编码/解码前对Output参数的TMemoryStream事先设置缓冲区大小,避免分多次向WINDOWS申请内存分配:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">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;
</pre>
</div>
<p>  对D7自带的BASE64单元改造后的源码:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">/// &lt;author&gt;cxg 2020-2-29&lt;/author&gt;
{
在编码/解码前对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);
functionEncodeString(const Input: string): string;
functionDecodeString(const Input: string): string;

implementation

const
EncodeTable: array 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 of Byte);
      3: (c: array of Char);
end;

procedure EncodePacket(const Packet: TPacket; NumChars: Integer; OutBuf: PChar);
begin
OutBuf := EnCodeTable shr 2];
OutBuf := EnCodeTable[((Packet.a shl 4) or (Packet.a shr 4)) and $0000003f];
if NumChars &lt; 2 then
    OutBuf := '='
else OutBuf := EnCodeTable[((Packet.a shl 2) or (Packet.a shr 6)) and $0000003f];
if NumChars &lt; 3 then
    OutBuf := '='
else OutBuf := EnCodeTable and $0000003f];
end;

function DecodePacket(InBuf: PChar; var nChars: Integer): TPacket;
begin
Result.a := (DecodeTable] shl 2) or
    (DecodeTable] shr 4);
NChars := 1;
if InBuf &lt;&gt; '=' then
begin
    Inc(NChars);
    Result.a := Byte((DecodeTable] shl 4) or (DecodeTable] shr 2));
end;
if InBuf &lt;&gt; '=' then
begin
    Inc(NChars);
    Result.a := Byte((DecodeTable] shl 6) or DecodeTable]);
end;
end;

procedure EncodeStream(Input, Output: TStream);
type
PInteger = ^Integer;
var
InBuf: array of Byte;
OutBuf: array 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 &lt; BytesRead do
    begin
      if BytesRead - I &lt; 3 then
      J := BytesRead - I
      else J := 3;
      Packet.i := 0;
      Packet.b0 := InBuf;
      if J &gt; 1 then
      Packet.b1 := InBuf;
      if J &gt; 2 then
      Packet.b2 := InBuf;
      EncodePacket(Packet, J, BufPtr);
      Inc(I, 3);
      Inc(BufPtr, 4);
      Inc(K, 4);
//      if K &gt; 75 then    //rem by cxg 每隔76个字符,就强制回车换行。将其注释掉
//      begin
//      BufPtr := #$0D;
//      BufPtr := #$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 of Char;
OutBuf: array 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, (SizeOf(InBuf)-IdxEnd));
      EndReached := CntRead &lt; (SizeOf(InBuf)-IdxEnd);
      Idx := IdxEnd;
      IdxEnd := CntRead + IdxEnd;
      while (Idx &lt; IdxEnd) do
      begin
      if not (InBuf in ['0'..'9','A'..'Z','a'..'z','+','/','=']) then
      begin
          Dec(IdxEnd);
          if Idx &lt; IdxEnd then
            Move(InBuf, InBuf, 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 &lt; BytesRead do
    begin
      Packet := DecodePacket(InBufPtr, J);
      K := 0;
      while J &gt; 0 do
      begin
      OutBufPtr^ := Char(Packet.a);
      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.
</pre>
</div>
<p>  </p>
<p>&nbsp;</p>

</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自博客园,作者:{咏南中间件},转载请注明原文链接:https://www.cnblogs.com/hnxxcxg/p/11100160.html</p><br><br>
来源:https://www.cnblogs.com/hnxxcxg/p/11100160.html
頁: [1]
查看完整版本: Delphi BASE64单元EncdDecd的修改