Delphi-改进获取文件MD5 Hash方法

2022-11-16 16:24:14 作者:admin

本文整理自网络,侵删。

 序言之前所说的获取文件MD5方法有性能问题,没多久我就遇到了,程序假死,卡顿。因此将获取文件MD5的方法改了一下,并测试了一下,大概性能提升了5倍,获取同一个文件的MD5,老方法用时是新方法的6倍。
改进原始获取文件MD5的方法:
// uses IdHashMessageDigestFunction StreamToMD5(s: TFileStream): string;var  MD5Encode: TIdHashMessageDigest5;begin  MD5Encode := TIdHashMessageDigest5.Create;  try    result := MD5Encode.HashStreamAsHex(s);  finally    MD5Encode.Free;  end;end;Copy改进后的方法:
// uses System.HashFunction GetFileHashMD5(FileName: String): String;var  HashMD5: THashMD5;  BufLen, Readed: integer;  Stream: TFileStream;  Buffer: Pointer;
begin  HashMD5 := THashMD5.Create;  BufLen := 16 * 1024;  Buffer := AllocMem(BufLen);  try    Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);    try      while Stream.Position < Stream.size do      begin        Readed := Stream.Read(Buffer^, BufLen);        if Readed > 0 then        begin          HashMD5.update(Buffer^, Readed);        end;      end;    finally      Stream.Free;    end;  finally    FreeMem(Buffer)  end;
  result := HashMD5.HashAsString.ToUpper;end;Copy测试结果文件大小原方法用时新方法用时1KB00:00:00.01300:00:00.00110KB00:00:00.02000:00:00.001100KB00:00:00.01000:00:00.0011MB00:00:00.06900:00:00.00810MB00:00:00.45500:00:00.091100MB00:00:04.33800:00:00.7711GB00:00:36.30600:00:07.4512GB00:01:13:21800:00:15:1013GB00:02:19:97700:00:23:1194GB00:02:25:50200:00:30:106以上测试结果肯定有偏差,因此将测试程序源码附上,以供需要的参考,程序界面:

unit Unit3;
interface
uses  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Hash, IdHashMessageDigest,  Vcl.StdCtrls, System.Math, IdGlobalProtocols;
type  TForm2 = class(TForm)    OpenDialog1: TOpenDialog;    Button1: TButton;    Button2: TButton;    Label1: TLabel;    Label2: TLabel;    Label3: TLabel;    Label4: TLabel;    Label5: TLabel;    Label6: TLabel;    Label7: TLabel;    Label8: TLabel;    procedure Button1Click(Sender: TObject);    procedure Button2Click(Sender: TObject);  private    { Private declarations }  public    { Public declarations }  end;
var  Form2: TForm2;  Function TransFloatToStr(Avalue: Double; ADigits: integer): String;
implementation
{$R *.dfm}
Function StreamToMD5(s: TFileStream): string;var  MD5Encode: TIdHashMessageDigest5;begin  MD5Encode := TIdHashMessageDigest5.Create;  try    result := MD5Encode.HashStreamAsHex(s);  finally    MD5Encode.Free;  end;end;
Function GetFileHashMD5(FileName: String): String;var  HashMD5: THashMD5;  BufLen, Readed: integer;  Stream: TFileStream;  Buffer: Pointer;
begin  HashMD5 := THashMD5.Create;  BufLen := 16 * 1024;  Buffer := AllocMem(BufLen);  try    Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);    try      while Stream.Position < Stream.size do      begin        Readed := Stream.Read(Buffer^, BufLen);        if Readed > 0 then        begin          HashMD5.update(Buffer^, Readed);        end;      end;    finally      Stream.Free;    end;  finally    FreeMem(Buffer)  end;
  result := HashMD5.HashAsString.ToUpper;end;

function TransBytesToSize(Bytes: integer): String;var  temp: String;begin  if Bytes < 1024 then { 字节 }  begin    result := IntToStr(Bytes) + ' Byte';  end
  else if Bytes < 1024 * 1024 then { KB }  begin    temp := TransFloatToStr(Bytes / 1024, 2);    result := temp + ' KB';  end
  else if Bytes < 1024 * 1024 * 1024 then { MB }  begin    temp := TransFloatToStr(Bytes / (1024 * 1024), 2);    result := temp + ' MB';  end
  else { GB }  begin    temp := TransFloatToStr(Bytes / (1024 * 1024 * 1024), 2);    result := temp + ' GB';  endend;

Function TransFloatToStr(Avalue: Double; ADigits: integer): String;var  v: Double;  p: integer;  e: String;begin  if abs(Avalue) < 1 then  begin    result := FloatToStr(Avalue);    p := Pos('E', result);    if p > 0 then    begin      e := copy(result, p, length(result));      setlength(result, p - 1);      v := RoundTo(StrToFloat(result), -ADigits);      result := FloatToStr(v) + e;    end    else      result := FloatToStr(RoundTo(Avalue, -ADigits));  end  else    result := FloatToStr(RoundTo(Avalue, -ADigits));end;

procedure TForm2.Button1Click(Sender: TObject);var  path: string;  FileName: string;  MD5: string;  bytes: Integer;  size: string;  d1 : TDateTime;begin  if OpenDialog1.Execute then  begin    FileName := ExtractFileName(OpenDialog1.FileName);    path := OpenDialog1.FileName;    d1 := Now();    MD5 := StreamToMD5(TFileStream.Create(path, fmOpenRead or fmShareDenyWrite));    Label4.Caption := FormatDateTime('hh:nn:ss.zzz', (Now-d1));    bytes := FileSizeByName(path);    size := TransBytesToSize(bytes);    Label2.Caption := MD5;    Label3.Caption := size;  end;
end;
procedure TForm2.Button2Click(Sender: TObject);var  path: string;  FileName: string;  MD5: string;  bytes: Integer;  size: string;  d2: TDateTime;begin  if OpenDialog1.Execute then  begin    FileName := ExtractFileName(OpenDialog1.FileName);    path := OpenDialog1.FileName;    d2 := Now();    MD5 := GetFileHashMD5(path);    Label8.Caption := FormatDateTime('hh:nn:ss.zzz', (Now-d2));    bytes := FileSizeByName(path);    size := TransBytesToSize(bytes);    Label6.Caption := MD5;    Label7.Caption := size;
  end;end;
end.

相关阅读 >>

Delphi 我的电脑连接到 internet 了吗?

Delphi 详解variant 的相关函数

Delphi 如何解析网址?

Delphi单元文件基本结构

Delphi timage 加上滚动条方法

Delphi if pos 多条件判断用法交流

Delphi 启动程序隐藏主窗体

Delphi通过窗口标题结束指定进程函数

Delphi中的sender:tobject对象解析

Delphi程序与chm帮助关联的简单实现

更多相关阅读请进入《Delphi》频道 >>



在线咨询 拨打电话