delphi-改进获取文件MD5 Hash方法  
官方Delphi 学习QQ群: 682628230(三千人)
频道

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
测试结果
文件大小 原方法用时 新方法用时
1KB 00:00:00.013 00:00:00.001
10KB 00:00:00.020 00:00:00.001
100KB 00:00:00.010 00:00:00.001
1MB 00:00:00.069 00:00:00.008
10MB 00:00:00.455 00:00:00.091
100MB 00:00:04.338 00:00:00.771
1GB 00:00:36.306 00:00:07.451
2GB 00:01:13:218 00:00:15:101
3GB 00:02:19:977 00:00:23:119
4GB 00:02:25:502 00: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.

推荐分享
图文皆来源于网络,内容仅做公益性分享,版权归原作者所有,如有侵权请告知删除!
 

Copyright © 2014 DelphiW.com 开发 源码 文档 技巧 All Rights Reserved
晋ICP备14006235号-8 晋公网安备 14108102000087号

执行时间: 0.19118905067444 seconds