Created
March 3, 2022 17:28
-
-
Save dbaudisch/f1f144b172be14cfe65248f43a3adcc8 to your computer and use it in GitHub Desktop.
My take on the concurrent checksum calculator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"crypto/sha256" | |
"fmt" | |
"io/fs" | |
"io/ioutil" | |
"os" | |
"path/filepath" | |
"sync" | |
"time" | |
) | |
const maxConcProc = 5 | |
var wg sync.WaitGroup | |
type File struct { | |
path string | |
hash [32]byte | |
dur time.Duration | |
skipped bool | |
} | |
var fileCounter Counter | |
var skipCounter Counter | |
type Counter struct { | |
mu sync.Mutex | |
count uint | |
} | |
func main() { | |
paths := os.Args[1:] | |
if len(paths) == 0 { | |
paths = append(paths, ".") | |
} | |
files := make(chan *File, 10) | |
for i := 0; i < maxConcProc; i++ { | |
go worker(files) | |
wg.Add(1) | |
} | |
for _, p := range paths { | |
readDir(p, files) | |
} | |
close(files) | |
wg.Wait() | |
fmt.Printf("\n[Result]\nHashes calculated: %d\nFiles skipped: %d", fileCounter.count, skipCounter.count) | |
} | |
func readDir(root string, files chan<- *File) { | |
filepath.WalkDir(root, func(p string, e fs.DirEntry, err error) error { | |
if err != nil { | |
skipCounter.Inc() | |
return nil | |
} | |
if !e.IsDir() { | |
files <- &File{path: p} | |
} | |
return nil | |
}) | |
} | |
func worker(files <-chan *File) { | |
for { | |
file, ok := <-files | |
if !ok { | |
break | |
} | |
file.calcHash() | |
if !file.skipped { | |
fmt.Println(file) | |
} | |
} | |
wg.Done() | |
} | |
func (f *File) calcHash() { | |
start := time.Now() | |
input, err := ioutil.ReadFile(f.path) | |
if err != nil { | |
f.skipped = true | |
skipCounter.Inc() | |
return | |
} | |
f.hash = sha256.Sum256(input) | |
f.dur = time.Since(start) | |
fileCounter.Inc() | |
} | |
func (f *File) String() string { | |
return fmt.Sprintf("%x = SHA256( %s ) took %s", f.hash, f.path, f.dur) | |
} | |
func (c *Counter) Inc() { | |
c.mu.Lock() | |
c.count++ | |
c.mu.Unlock() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice!