[go语言]磁盘重复文件查找
本帖最后由 hahaxi 于 2021-1-14 21:20 编辑练手做的小工具
查找本地指定路径下md相同的文件
顺便把图片,视频单独展示出来
主分支使用go levelDB,不需要额外配置数据库,需要使用数据库的可切换到mysql分支
gitee传送门
https://gitee.com/cilidm/duplicate_file
> 开始:
>
>MySQL版本需要修改app/db/mysql下数据库配置,LevelDB版本不需要
>
> 初次执行 go run main.go -n -p /home/src
>
> 再次执行 go run main.go
> -n 执行新任务
> -p 检测路径
>
> 如果不需要检测md 请加上 -md false
> 初次执行会先扫描文件并检查重复文件,这个步骤耗时比较长,执行完后 可以在浏览器 http://localhost:8000 查看
> 没有安装golang环境的,可以在命令行执行二进制文件,首次执行要追加-n -p指令,会在目录下生成views网页文件夹以及static js文件夹。
> runtime文件夹保存日志及levelDB数据文件
> 测试环境 darwin10.15.5
本帖最后由 hahaxi 于 2021-1-14 21:21 编辑
顺便分享个图片转webp的代码
jpg2webp
根据磁盘路径转换图片为webp
使用方式 linux、mac
```
./file_wale_2webp_xxx -s /home/pic -t /home/webp
-s 源地址
-d 目标地址
```
package main
import (
"bytes"
"crypto/md5"
"errors"
"flag"
"fmt"
"image"
"image/gif"
"image/jpeg"
"image/png"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"sync/atomic"
"time"
"github.com/chai2010/webp"
"github.com/cilidm/toolbox/logging"
"golang.org/x/image/bmp"
)
func PathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
os.MkdirAll(path, os.ModePerm)
return false, nil
}
return false, err
}
// 判断字符串是否在数组里
func IsContain(items []string, item string) bool {
for _, eachItem := range items {
if eachItem == item {
return true
}
}
return false
}
func GetMd5(path string) (string, error) {
f, err := os.Open(path)
if err != nil {
return "", err
}
defer f.Close()
md5hash := md5.New()
if _, err := io.Copy(md5hash, f); err != nil {
return "", err
}
return fmt.Sprintf("%x", md5hash.Sum(nil)), nil
}
func walkDir(dir, dst string) {
PathExists(dst)
var num uint64 = 1
filepath.Walk(dir, func(p string, info os.FileInfo, err error) error {
if info.IsDir() == false {
ext := path.Ext(info.Name())
if IsContain([]string{".jpg", ".jpeg", ".png", ".bmp", ".gif"}, ext) {
maxChan <- struct{}{}
atomic.AddUint64(&num, 1)
md, err := GetMd5(p)
if err != nil {
logging.Error(err.Error())
return nil
}
webpFile := dst + "/" + md + ".webp"
if CheckFileIsExist(webpFile) == false {
go change2webp(p, webpFile, 90, true)
}
}
}
return nil
})
close(maxChan)
searchDone <- struct{}{}
}
/**
* 判断文件是否存在存在返回 true 不存在返回false
*/
func CheckFileIsExist(filename string) bool {
var exist = true
if _, err := os.Stat(filename); os.IsNotExist(err) {
exist = false
}
return exist
}
func change2webp(p1, p2 string, quality float32, Log bool) {
fmt.Println("begin", p1)
err := WebpEncoder(p1, p2, quality, Log)
if err != nil {
logging.Error(err.Error())
}
<-maxChan
}
func WebpEncoder(p1, p2 string, quality float32, Log bool) (err error) {
logging.Debug("img path :", path.Base(p1), ",quality is :", quality)
var buf bytes.Buffer
var img image.Image
data, err := ioutil.ReadFile(p1)
if err != nil {
return err
}
contentType := GetFileContentType(data[:512])
if strings.Contains(contentType, "jpeg") {
img, _ = jpeg.Decode(bytes.NewReader(data))
} else if strings.Contains(contentType, "png") {
img, _ = png.Decode(bytes.NewReader(data))
} else if strings.Contains(contentType, "bmp") {
img, _ = bmp.Decode(bytes.NewReader(data))
} else if strings.Contains(contentType, "gif") {
logging.Warn("Gif support is not perfect!")
img, _ = gif.Decode(bytes.NewReader(data))
}
if img == nil {
msg := "image file " + path.Base(p1) + " is corrupted or not supported"
err = errors.New(msg)
return err
}
if err = webp.Encode(&buf, img, &webp.Options{Lossless: false, Quality: quality}); err != nil {
return err
}
if err = ioutil.WriteFile(p2, buf.Bytes(), 0644); err != nil {
return err
}
if Log {
logging.Info("Save to " + p2 + " ok!")
}
return nil
}
func GetFileContentType(buffer []byte) string {
contentType := http.DetectContentType(buffer)
return contentType
}
var (
maxChan = make(chan struct{}, 10)
done = make(chan bool)
searchDone = make(chan struct{})
source string
dst string
)
func monitorDone() {
select {
case <-searchDone:
for {
if len(maxChan) == 0 {
done <- true
break
}
}
}
}
func init() {
go monitorDone()
flag.StringVar(&source, "s", "", "源地址")
flag.StringVar(&dst, "d", "", "目标地址")
flag.Parse()
}
func main() {
if source == "" || dst == "" {
log.Fatal("请输入源地址及目标地址")
}
start := time.Now()
walkDir(source, dst)
select {
case <-done:
fmt.Println("文件更新完毕,耗时", time.Since(start))
}
}
页:
[1]