ios - Swift 计算大文件的 MD5 校验和

标签 ios swift md5 checksum commoncrypto

我正在为大型视频文件创建 MD5 校验和。我目前正在使用代码:

extension NSData {
func MD5() -> NSString {
    let digestLength = Int(CC_MD5_DIGEST_LENGTH)
    let md5Buffer = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLength)

    CC_MD5(bytes, CC_LONG(length), md5Buffer)
    let output = NSMutableString(capacity: Int(CC_MD5_DIGEST_LENGTH * 2))
    for i in 0..<digestLength {
        output.appendFormat("%02x", md5Buffer[i])
    }

    return NSString(format: output)
    }
}

但这会创建一个内存缓冲区,对于大型视频文件来说并不理想。 Swift 中是否有一种方法可以计算读取文件流的 MD5 校验和,从而使内存占用最小?

最佳答案

您可以分 block 计算 MD5 校验和,如图所示 例如在 Is there a MD5 library that doesn't require the whole input at the same time? .

这是一个使用 Swift 的可能实现(现在更新为 Swift 5)

import CommonCrypto

func md5File(url: URL) -> Data? {

    let bufferSize = 1024 * 1024

    do {
        // Open file for reading:
        let file = try FileHandle(forReadingFrom: url)
        defer {
            file.closeFile()
        }

        // Create and initialize MD5 context:
        var context = CC_MD5_CTX()
        CC_MD5_Init(&context)

        // Read up to `bufferSize` bytes, until EOF is reached, and update MD5 context:
        while autoreleasepool(invoking: {
            let data = file.readData(ofLength: bufferSize)
            if data.count > 0 {
                data.withUnsafeBytes {
                    _ = CC_MD5_Update(&context, $0.baseAddress, numericCast(data.count))
                }
                return true // Continue
            } else {
                return false // End of file
            }
        }) { }

        // Compute the MD5 digest:
        var digest: [UInt8] = Array(repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
        _ = CC_MD5_Final(&digest, &context)

        return Data(digest)

    } catch {
        print("Cannot open file:", error.localizedDescription)
        return nil
    }
}

需要自动释放池来释放返回的内存 file.readData(),没有它整个(可能很大的)文件 将被加载到内存中。感谢 Abhi Beckert 注意到这一点 并提供实现。

如果您需要将摘要作为十六进制编码的字符串,则更改 返回类型为 String? 并替换

return digest

let hexDigest = digest.map { String(format: "%02hhx", $0) }.joined()
return hexDigest

关于ios - Swift 计算大文件的 MD5 校验和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42935148/

相关文章:

ios - 代表没有回应

swift - 在 Swift 中评估对象类型

java - Matlab-Java MD5 给出错误的哈希值

c# - 计算散列,而不是一次将整个缓冲区都放在内存中

PHP MD5 Performance = 处理器很饿吗?

ios - 使用 performBackgroundTask 更新 NSFetchedResultsController

iOS:Google Maps API - 禁用信息窗口点击事件

ios - 使用带有完成处理程序的循环在多个节点上使用单个 SKAction 动画

ios - 使用 UIKit Dynamics 动画自动布局支持 View

ios - iOS 数组索引超出范围