首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用VBA为大型文件生成MD5散列?

如何使用VBA为大型文件生成MD5散列?
EN

Stack Overflow用户
提问于 2016-03-31 08:51:26
回答 2查看 5.4K关注 0票数 5

我有以下函数为文件生成md5散列。这些函数对于小文件非常有用,但是当我尝试散列超过250 MB的文件时,会崩溃并生成运行时错误7-内存不足的(我实际上不知道它的确切大小,但低于200 MB的文件工作得很好)。

我不明白它为什么会在一定的尺寸下断裂,所以如果有人能给我一些启示,我会非常感激的。

另外,我能做些什么来使函数处理更大的文件吗?我打算在一个更大的工具中使用这些函数,在这个工具中,我需要为未知大小的文件生成散列。大多数功能都足够小,可以让当前的函数工作,但我也必须能够处理大型文件。

我从投票最多的答案中得到了我当前的功能-- How to get the MD5 hex hash for a file using VBA?

代码语言:javascript
运行
复制
Public Function FileToMD5Hex(ByVal strFileName As String) As String
Dim varEnc           As Variant
Dim varBytes         As Variant
Dim strOut           As String
Dim intPos           As Integer

Set varEnc = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider")

'Convert the string to a byte array and hash it
varBytes = GetFileBytes(strFileName)
varBytes = varEnc.ComputeHash_2((varBytes))

'Convert the byte array to a hex string
For intPos = 1 To LenB(varBytes)
   strOut = strOut & LCase(Right("0" & Hex(AscB(MidB(varBytes, intPos, 1))), 2))
Next

FileToMD5Hex = strOut

Set varEnc = Nothing

End Function

Private Function GetFileBytes(ByVal strPath As String) As Byte()
Dim lngFileNum          As Long
Dim bytRtnVal()         As Byte

lngFileNum = FreeFile

'If file exists, get number of bytes
If LenB(Dir(strPath)) Then
   Open strPath For Binary Access Read As lngFileNum
   ReDim bytRtnVal(LOF(lngFileNum)) As Byte
   Get lngFileNum, , bytRtnVal
   Close lngFileNum
Else
   MsgBox "Filen finns inte" & vbCrLf & "Avbryter", vbCritical, "Filen hittades inte"
   Exit Function
End If

GetFileBytes = bytRtnVal
Erase bytRtnVal

End Function

谢谢

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-03-31 10:41:56

看来你达到了记忆极限。更好的方法是逐块计算文件的MD5:

代码语言:javascript
运行
复制
Public Function ComputeMD5(filepath As String) As String
  Dim buffer() As Byte, svc As Object, hFile%, blockSize&, i&
  blockSize = 2 ^ 16

  ' open the file '

  If Len(Dir(filepath)) Then Else Err.Raise 5, , "file not found" & vbCr & filepath

  hFile = FreeFile
  Open filepath For Binary Access Read As hFile

  ' allocate buffer '

  If LOF(hFile) < blockSize Then blockSize = ((LOF(hFile) + 1024) \ 1024) * 1024
  ReDim buffer(0 To blockSize - 1)

  ' compute hash '

  Set svc = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider")

  For i = 1 To LOF(hFile) \ blockSize
    Get hFile, , buffer
    svc.TransformBlock buffer, 0, blockSize, buffer, 0
  Next

  Get hFile, , buffer
  svc.TransformFinalBlock buffer, 0, LOF(hFile) Mod blockSize
  buffer = svc.Hash

  ' cleanup '

  svc.Clear
  Close hFile

  ' convert to an hexa string '

  ComputeMD5 = String$(32, "0")

  For i = 0 To 15
     Mid$(ComputeMD5, i + i + 2 + (buffer(i) > 15)) = Hex(buffer(i))
  Next

End Function
票数 7
EN

Stack Overflow用户

发布于 2018-05-02 09:37:53

这是FlorentB的一个扩展,它对我非常有用,直到我的文件超过了2GB的LOF()大小限制。

我试图通过其他方式调整文件长度,如下所示:

代码语言:javascript
运行
复制
Public Function ComputeMD5(filepath As String) As String
    If Len(Dir(filepath)) Then Else Err.Raise 5, , "File not found." & vbCr & filepath

    Dim blockSize As Long: blockSize = 2 ^ 20
    Dim blockSize_f As Double
    Dim buffer() As Byte
    Dim fileLength As Variant
    Dim hFile As Integer
    Dim n_Reads As Long
    Dim i As Long
    Dim svc As Object: Set svc = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider")

    fileLength = DecGetFileSize(filepath)
    If fileLength < blockSize Then blockSize = ((fileLength + 1024) \ 1024) * 1024
    ReDim buffer(0 To blockSize - 1)
    n_Reads = fileLength / blockSize
    blockSize_f = fileLength - (CDbl(blockSize) * n_Reads)

    hFile = FreeFile
    Open filepath For Binary Access Read As hFile
    For i = 1 To n_Reads
        Get hFile, i, buffer
        svc.TransformBlock buffer, 0, blockSize, buffer, 0
    Next i

    Get hFile, i, buffer
    svc.TransformFinalBlock buffer, 0, blockSize_f
    buffer = svc.Hash
    svc.Clear
    Close hFile

    ComputeMD5 = String$(32, "0")
    For i = 0 To 15
        Mid$(ComputeMD5, i + i + 2 + (buffer(i) > 15)) = Hex(buffer(i))
    Next

End Function

Public Function DecGetFileSize(fname As String) As Variant
    Dim fso As New FileSystemObject
    Dim f: Set f = fso.GetFile(fname)
    DecGetFileSize = CDec(f.Size)
    Set f = Nothing
    Set fso = Nothing
End Function

这一切都运行良好,返回一个字符串,但是该字符串不等于使用同一文件上的其他工具计算的MD5。

我不知道这种差异是从何而来的。

我已经检查和双重检查了filelength,n_reads,blockSize和blockSize_f,并且我确信这些值都是正确的。

Get函数有一些问题,如果我不明确告诉它块号,它就会死在块2048。

如有任何意见或建议,将不胜感激。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36328530

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档