package files import ( "errors" "io" "lab.evlic.cn/go/pkg/md5" "mime/multipart" "os" "path/filepath" "strings" "go.uber.org/zap" ) func FileSave(r io.Reader, dst string) (err error) { var ( fp string out io.WriteCloser ) fp = filepath.Dir(dst) err = DirCheck(fp) out, err = os.Create(dst) if err != nil { return err } defer out.Close() _, err = io.Copy(out, r) return } // FileMD5 计算文件 md5 值 func FileMD5(file string) (string, error) { f, err := os.Open(file) if err != nil { return "", err } info, err := f.Stat() if err != nil { return "", err } size := info.Size() return md5.Sum(f, size, BlockSize, ChunkSize) } func MultipartMD5(fh *multipart.FileHeader) (string, error) { f, err := fh.Open() if err != nil { return "", err } size := fh.Size return md5.Sum(f, size, BlockSize, ChunkSize) } const ( BlockSize = 1 << 10 ChunkSize = BlockSize << 2 ) var ( ErrorIsNotDir = errors.New("path is not dir. ") ) func DirCheck(dir string) (err error) { var fi os.FileInfo if fi, err = os.Stat(dir); err != nil { if !os.IsExist(err) || os.IsNotExist(err) { return DirMk(dir) } } if !fi.IsDir() { err = ErrorIsNotDir } return } func DirMk(dir string) error { return os.MkdirAll(dir, 0755) } const MaxScanDeep = 20 var maxDeepError = errors.New("scanMaxDeep") func IsScanMaxDeep(err error) bool { return errors.Is(err, maxDeepError) } // DirScan 扫描目录,on err skip func DirScan(dir string, h func(dir string, info os.FileInfo)) error { return dirScan(dir, h, 0) } func dirScanIgnore(name string) bool { return strings.HasPrefix(name, ".") || strings.Contains(strings.ToLower(name), "readme") } func dirScan(dir string, h func(dir string, info os.FileInfo), deep int) error { if deep > MaxScanDeep { return maxDeepError } dirs, err := os.ReadDir(dir) if err != nil { return err } var ( info os.FileInfo nextDir string ) for _, entry := range dirs { info, err = entry.Info() if err != nil { zap.L().Warn("scan err", zap.String("name", entry.Name()), zap.Error(err)) continue } if dirScanIgnore(info.Name()) { continue } h(dir, info) if entry.IsDir() { nextDir = filepath.Join(dir, info.Name()) if err = dirScan(nextDir, h, deep+1); err != nil { zap.L().Warn("scan err", zap.String("dirname", nextDir), zap.Error(err)) } } } return err } func PathAbs(path string) string { if filepath.IsAbs(path) { return path } abs, err := filepath.Abs(path) if err != nil { return path } return abs }