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 > 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;">/// <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);
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 < 2 then
OutBuf := '='
else OutBuf := EnCodeTable[((Packet.a shl 2) or (Packet.a shr 6)) and $0000003f];
if NumChars < 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 <> '=' then
begin
Inc(NChars);
Result.a := Byte((DecodeTable] shl 4) or (DecodeTable] shr 2));
end;
if InBuf <> '=' 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 < BytesRead do
begin
if BytesRead - I < 3 then
J := BytesRead - I
else J := 3;
Packet.i := 0;
Packet.b0 := InBuf;
if J > 1 then
Packet.b1 := InBuf;
if J > 2 then
Packet.b2 := InBuf;
EncodePacket(Packet, J, BufPtr);
Inc(I, 3);
Inc(BufPtr, 4);
Inc(K, 4);
// if K > 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 < (SizeOf(InBuf)-IdxEnd);
Idx := IdxEnd;
IdxEnd := CntRead + IdxEnd;
while (Idx < IdxEnd) do
begin
if not (InBuf in ['0'..'9','A'..'Z','a'..'z','+','/','=']) then
begin
Dec(IdxEnd);
if Idx < 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 < BytesRead do
begin
Packet := DecodePacket(InBufPtr, J);
K := 0;
while J > 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> </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]