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


本文整理自网络,侵删。

 
序言
之前所说的获取文件MD5方法有性能问题,没多久我就遇到了,程序假死,卡顿。因此将获取文件MD5的方法改了一下,并测试了一下,大概性能提升了5倍,获取同一个文件的MD5,老方法用时是新方法的6倍。

改进
原始获取文件MD5的方法:

// uses IdHashMessageDigest
Function StreamToMD5(s: TFileStream): string;
var
  MD5Encode: TIdHashMessageDigest5;
begin
  MD5Encode := TIdHashMessageDigest5.Create;
  try
    result := MD5Encode.HashStreamAsHex(s);
  finally
    MD5Encode.Free;
  end;
end;Copy
改进后的方法:

// uses System.Hash
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;Copy
测试结果
文件大小原方法用时新方法用时
1KB00:00:00.01300:00:00.001
10KB00:00:00.02000:00:00.001
100KB00:00:00.01000:00:00.001
1MB00:00:00.06900:00:00.008
10MB00:00:00.45500:00:00.091
100MB00:00:04.33800:00:00.771
1GB00:00:36.30600:00:07.451
2GB00:01:13:21800:00:15:101
3GB00:02:19:97700:00:23:119
4GB00: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';
  end
end;


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 调用系统图片查看器

Delphi 获取网卡物理地址之内存获取方式函数源码

Delphi scrollbox1滚动框鼠标滚轮

Delphi 随机函数单元urandomutils

Delphi 判断素数的简单例子

Delphi 服务器与客户端的时间同步

Delphi 怎么将一个流转换成字符串?或者将字符串转出一个流

Delphi2010中tresourcestream流使用

Delphi msxml 获取 api接口

Delphi 获取外部程序句柄与发送消息

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



打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...