我有这个go代码,该代码遍历目录文件树,并在其中生成每个文件的MD5哈希值,并将结果写入输出文件中。
package main
import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"os"
"path/filepath"
"sync"
)
func main() {
filePath := os.Args[1]
output := os.Args[2]
wg := &sync.WaitGroup{}
err := filepath.Walk(filePath, func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
wg.Add(1)
go func(path string) {
md5Sum, _ := md5File(path)
if err := writeToFile(path, md5Sum, output); err != nil {
panic(err)
}
wg.Done()
}(path)
}
return nil
})
if err != nil {
panic(err)
}
wg.Wait()
}
func md5File(filePath string) (string, error) {
file, err := os.Open(filePath)
if err != nil {
return "", err
}
defer file.Close()
hash := md5.New()
if _, err := io.Copy(hash, file); err != nil {
return "", err
}
checksum := hash.Sum(nil)
return string(hex.EncodeToString(checksum)), nil
}
func writeToFile(filePath, md5sum, output string) error {
file, err := os.OpenFile(output, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0755)
if err != nil {
return err
}
defer file.Close()
file.WriteString(fmt.Sprintf("%s %s\n", md5sum, filePath))
return file.Sync()
}
据我所知,它必然会在写入输出文件的某个时候陷入竞争状态,但绝不会。我的意思是我无数次执行了这段代码,从未遇到任何问题。甚至每次都会产生相同的结果。
那是为什么?我想念什么吗?
更新:当我说它必然会遇到竞争状况时,我的意思是在运行多个goroutine时,可能有多个goroutine希望同时写入文件。>
答案 0 :(得分:2)
当我说它必然会遇到竞争状况时,我的意思是说,当运行多个goroutine时,可能有多个goroutine希望同时写入文件。
多次打开文件不是问题。并且由于您显式使用O_APPEND
,因此写入之间不会发生不良交互。引用
来自man open:
O_APPEND ...
在每次write(2)之前,文件偏移都位于文件的末尾,就像使用lseek(2)一样。 文件偏移量的修改和写操作是单个原子步骤。