2017-07-14 115 views
1

我想製作一個基於md5校驗和檢查文件重複的程序。 不能確定我是否失去了一些東西或者不是,但這個函數讀取的XCode安裝的應用程序(它有一個像8GB)採用拉姆ioutil.ReadFile有更快的選擇嗎?

func search() { 
    unique := make(map[string]string) 
    files, err := ioutil.ReadDir(".") 
    if err != nil { 
     log.Println(err) 
    } 

    for _, file := range files { 
     fileName := file.Name() 
     fmt.Println("CHECKING:", fileName) 
     fi, err := os.Stat(fileName) 
     if err != nil { 
      fmt.Println(err) 
      continue 
     } 
     if fi.Mode().IsRegular() { 
      data, err := ioutil.ReadFile(fileName) 
      if err != nil { 
       fmt.Println(err) 
       continue 
      } 
      sum := md5.Sum(data) 
      hexDigest := hex.EncodeToString(sum[:]) 
      if _, ok := unique[hexDigest]; ok == false { 
       unique[hexDigest] = fileName 
      } else { 
       fmt.Println("DUPLICATE:", fileName) 
      } 
     } 
    } 
} 

的16GB按我調試的問題出在文件讀取 是有更好的方法來做到這一點? 謝謝

+0

嘗試'md5.New',結合'io.Copy'。看看[示例](https://golang.org/pkg/crypto/md5/#example_New_file)。 – putu

回答

4

Golang文檔中有一個example,它涵蓋了您的案例。

package main 

import (
    "crypto/md5" 
    "fmt" 
    "io" 
    "log" 
    "os" 
) 

func main() { 
    f, err := os.Open("file.txt") 
    if err != nil { 
     log.Fatal(err) 
    } 
    defer f.Close() 

    h := md5.New() 
    if _, err := io.Copy(h, f); err != nil { 
     log.Fatal(err) 
    } 

    fmt.Printf("%x", h.Sum(nil)) 
} 

對於你的情況,只要確保關閉循環中的文件,而不是推遲它們。或者把邏輯放到一個函數中。

3

聽起來像16GB RAM是你的問題,而不是速度本身。

不要用ReadFile將整個文件讀入一個變量; io.Copy從打開讀取器提供給散列/ md5提供的寫入器(md5.New返回嵌入io.Writer的hash.Hash)。這隻會一次複製一點點,而不是將所有文件都拉到RAM中。

這是一個在Go很多地方很有用的技巧;像text/templatecompress/gzipnet/http等包的工作在讀者和作家方面。有了它們,你通常不需要創建大型的[]bytestring;您可以將I/O接口彼此掛鉤,讓他們爲您傳遞各種內容。在垃圾收集語言中,保存內存也可以節省CPU工作。