目的是将当前可执行程序平级的某个目录生成check list文件,表明是文件还是目录,如果是文件生成md5值。还可以根据check list文件来判断目录里面的内容是否完整,如果是目录就判断目录是否存在,如果是文件就比对md5值是否一样。
生成check list 文件:
checkfilelist.exe -name app -mode write
校验目录是否完整:
checkfilelist.exe -name app -mode check
代码如下:
package main
import (
"bufio"
"crypto/md5"
"encoding/json"
"flag"
"fmt"
"io"
"io/fs"
"os"
"os/exec"
"path"
"path/filepath"
)
const CHECKLISTNAME = "checklist.json"
type DirCheck struct {
Name string `json:"name"`
Items []Item
}
type Item struct {
Type int `json:"type"`
Path string `json:"path"`
Md5 string `json:"md5"`
}
func main() {
var dirname string
var mode string
flag.StringVar(&dirname, "name", "", "directory name")
flag.StringVar(&mode, "mode", "", "write or check")
flag.Parse()
currentfile, _ := exec.LookPath(os.Args[0])
currentpath, _ := filepath.Abs(currentfile)
currentdir := path.Join(currentpath, "..")
fmt.Println("src dir:", currentdir, "name:", dirname)
if mode == "write" {
Write(currentdir, dirname)
fmt.Println("write success")
} else if mode == "check" {
err := Check(currentdir, CHECKLISTNAME)
if err != nil {
panic(err)
} else {
fmt.Println("check success")
}
} else {
panic("mode error")
}
}
func Write(currentdir string, dirname string) {
srcdir := path.Join(currentdir, dirname)
fmt.Println("src dir:", srcdir)
dc := DirCheck{}
dc.Name = filepath.Base(srcdir)
filepath.WalkDir(srcdir, func(pathstr string, d fs.DirEntry, err error) error {
abspath := pathstr[len(srcdir):]
if len(abspath) == 0 {
return nil
}
filetype := 0
md5str := ""
if d.IsDir() {
filetype = 1
} else {
filetype = 2
md5str, err = MD5File(pathstr)
if err != nil {
fmt.Println("md5 error, path:", pathstr)
panic(err)
}
}
dc.Items = append(dc.Items, Item{
Type: filetype,
Path: abspath,
Md5: md5str,
})
fmt.Println(abspath)
return nil
})
b, err := json.MarshalIndent(dc, "", " ")
if err != nil {
panic(err)
}
if err := os.WriteFile(CHECKLISTNAME, b, os.ModePerm); err != nil {
panic(err)
}
}
func Check(currentdir string, name string) error {
checklistpath := path.Join(currentdir, name)
b, err := os.ReadFile(checklistpath)
if err != nil {
return err
}
var dc DirCheck
if err := json.Unmarshal(b, &dc); err != nil {
return err
}
for _, item := range dc.Items {
pathstr := path.Join(currentdir, dc.Name, item.Path)
if item.Type == 1 {
if !FileExists(pathstr) {
return fmt.Errorf("directory not found, dir:%s", pathstr)
}
} else if item.Type == 2 {
md5str, err := MD5File(pathstr)
if err != nil {
return err
}
if md5str != item.Md5 {
return fmt.Errorf("md5 not match, path:%s", pathstr)
}
}
}
return nil
}
func MD5File(file string) (string, error) {
f, err := os.Open(file)
if err != nil {
return "", err
}
defer f.Close()
r := bufio.NewReader(f)
h := md5.New()
_, err = io.Copy(h, r)
if err != nil {
return "", err
}
return fmt.Sprintf("%X", h.Sum(nil)), nil
}
func FileExists(path string) bool {
_, err := os.Stat(path)
if err != nil {
if os.IsExist(err) {
return true
}
return false
}
return true
}