// 這裏獲取的是 FileInfo 對象 fi, _ := os.Stat(filepath)
FileInfo 定義以下:併發
type FileInfo interface { Name() string // 文件的名字 Size() int64 // 普通文件返回值表示其大小;其餘文件的返回值含義各系統不一樣 Mode() FileMode // 文件的模式位 ModTime() time.Time // 文件的修改時間 IsDir() bool // 等價於Mode().IsDir() Sys() interface{} // 底層數據來源(能夠返回nil) }
標準庫提供了 filepath.Walk 遍歷目錄,可是這個函數是串行的,當目錄比較多時,性能不好,
這裏建議本身實現,大體步驟以下:函數
import ( "flag" "fmt" "io/ioutil" "os" "path/filepath" "sync" "time" ) //獲取目錄dir下的文件大小 func walkDir(dir string, wg *sync.WaitGroup, fileSizes chan<- int64) { defer wg.Done() for _, entry := range dirents(dir) { if entry.IsDir() {//目錄 wg.Add(1) subDir := filepath.Join(dir, entry.Name()) go walkDir(subDir, wg, fileSizes) } else { fileSizes <- entry.Size() } } } //sema is a counting semaphore for limiting concurrency in dirents var sema = make(chan struct{}, 20) //讀取目錄dir下的文件信息 func dirents(dir string) []os.FileInfo { sema <- struct{}{} defer func() { <-sema }() entries, err := ioutil.ReadDir(dir) if err != nil { fmt.Fprintf(os.Stderr, "du: %v\n", err) return nil } return entries } //輸出文件數量的大小 func printDiskUsage(nfiles, nbytes int64) { fmt.Printf("%d files %.1f GB\n", nfiles, float64(nbytes)/1e9) } //提供-v 參數會顯示程序進度信息 var verbose = flag.Bool("v", false, "show verbose progress messages") func Start() { flag.Parse() roots := flag.Args()//須要統計的目錄 if len(roots) == 0 { roots = []string{"."} } fileSizes := make(chan int64) var wg sync.WaitGroup for _, root := range roots { wg.Add(1) go walkDir(root, &wg, fileSizes) } go func() { wg.Wait() //等待goroutine結束 close(fileSizes) }() var tick <-chan time.Time if *verbose { tick = time.Tick(100 * time.Millisecond) //輸出時間間隔 } var nfiles, nbytes int64 loop: for { select { case size, ok := <-fileSizes: if !ok { break loop } nfiles++ nbytes += size case <-tick: printDiskUsage(nfiles, nbytes) } } printDiskUsage(nfiles, nbytes) }