package main import ( "fmt" "os" "path/filepath" "sync" ) // go-fakedu - toy approximation of the du (disk usage) // toy program to learn go concurrency structures type FileInfo struct { path string info os.FileInfo } type SafeArraySlice struct { m sync.Mutex data []int64 } func NewSafeIntArraySlice() *SafeArraySlice { return &SafeArraySlice{ m: sync.Mutex{}, data: make([]int64, 100), } } func (a *SafeArraySlice) AppendIntArraySlice(i int64) { a.m.Lock() defer a.m.Unlock() a.data = append(a.data, i) } func enumFiles(dir string) { fileCh := make(chan FileInfo) errCh := make(chan error, 1) // Buffered channel to prevent blocking var wg sync.WaitGroup file_size_storage := NewSafeIntArraySlice() // Start a goroutine for walking the file tree go func() { // Send any errors to the errCh channel errCh <- filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if !info.IsDir() { fileCh <- FileInfo{path, info} } return nil }) close(fileCh) // Close the fileCh channel after walking is done }() // Start a goroutine to process files go func() { for path := range fileCh { wg.Add(1) go func(fInfo FileInfo) { defer wg.Done() // Process file (e.g., read, hash, etc.) fmt.Println(fInfo.path, fInfo.info.Size()) file_size_storage.AppendIntArraySlice(fInfo.info.Size()) }(path) } wg.Wait() close(errCh) // Close the errCh channel after all processing is done }() // Check for errors from filepath.Walk if err := <-errCh; err != nil { fmt.Println("Error walking the file tree:", err) return } // Not getting a lock here as by now we know // that nothing is currently accessing this slice var size int64 = 0 for _, value := range file_size_storage.data { size = size + value } fmt.Println("Total size: ", float32(size)/(1<<20), "MBs") } func main() { args := os.Args if len(args) < 2 { fmt.Println("Must provide path to directory") os.Exit(1) } enumFiles(args[1]) }