2017-03-21 4 views
4

大きなビデオファイルのMD5チェックサムの作成に取り組んでいます。私は現在のコードを使用しています:大きなファイルの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チェックサムを計算する方法があるので、メモリフットプリントは最小限に抑えられますか?

+0

によって

return digest 

を交換するには、 'CC_MD5_Init'の適切な組み合わせを使用して調べてください'CC_MD5_Update'、および' CC_MD5_Final'を含む。 – rmaddy

答えて

8

たとえば、 のように、チャンク内でMD5チェックサムを計算できます。 Is there a MD5 library that doesn't require the whole input at the same time?にあります。それなしで、

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, numericCast(data.count)) 
       } 
       return true // Continue 
      } else { 
       return false // End of file 
      } 
     }) { } 

     // Compute the MD5 digest: 
     var digest = Data(count: Int(CC_MD5_DIGEST_LENGTH)) 
     digest.withUnsafeMutableBytes { 
      _ = CC_MD5_Final($0, &context) 
     } 

     return digest 

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

自動解放プールが file.readData()によって返されたメモリを解放するために必要とされる全体の(潜在的に巨大な) がメモリにロードされますファイル:

はここスウィフトを使用して可能な実装です。 に気づいて実装を提供してくれたAbhi Beckertに感謝します。

あなたは16進数の文字列としてダイジェストが必要な場合は、その後String?に 戻り値の型を変更し、

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

このコードを使用している人は、ファイル全体を現在の自動解放プールに保存していて、数十ギガバイトのメモリを消費する可能性があるため、私が行った編集に合わせて更新したいと思うでしょう。 –

+0

@AbhiBeckert:確かに、それは大きな違いになります。更新していただきありがとうございます!追加の終了変数を取り除くためにコードを少し修正しましたが、これはまったく個人的な選択の問題です。 –

関連する問題