go 实现 md5 批量修改
md5
是什么
MD5
是消息摘要算法(Message Digest Algorithm 5)的缩写,它是一种常见的哈希函数,用于将任意长度的数据转换为固定长度(通常是128位)的哈希值。MD5
算法广泛用于计算数据的校验和、数字签名、数据完整性验证等方面。
MD5
算法对输入数据产生一个128位的哈希值,通常表示为一个32位的十六进制数。无论输入数据的大小,得到的哈希值长度都保持不变。它具有以下特点:
- 快速计算:
MD5
算法的运算速度较快,适用于对大量数据进行校验和计算。 - 唯一性:不同的输入数据通常会生成不同的
MD5
哈希值,因此可以用于验证数据的完整性和唯一性。 - 不可逆性:无法从
MD5
哈希值反推出原始输入数据,因为MD5
算法是单向的,即只能将数据转换成哈希值,不能将哈希值还原成原始数据。
文件的 md5
文件的 MD5
原理基本上与 MD5
算法的原理相同,只是针对文件数据的处理方式略有不同。MD5
算法将任意长度的数据转换为128位的哈希值,文件的 MD5
原理也是将文件数据进行处理,得到一个固定长度的 MD5
哈希值。
实现原理
遍历文件,然后再每个文件的最后加几个字符
实现代码
package main
import (
"crypto/md5"
"encoding/hex"
"flag"
"fmt"
"io"
"io/fs"
"os"
"os/signal"
"path/filepath"
"strings"
"sync"
"time"
)
var start_path string
var append_content string
var success_count = 0
var fail_count = 0
var file_index = 0
// var max_thread_num = 10
func visit(path string, info os.FileInfo, err error) error {
defer func() {
if err := recover(); err != nil {
fmt.Printf("处理[%s]时发生错误\n", info.Name())
} else if !info.IsDir() {
fail_count--
success_count++
}
}()
if err != nil {
fmt.Println("Error:", err)
return nil
}
if !info.IsDir() {
fail_count++
md5, _ := calculateMD5(path)
appendFileToChar(path, []byte(append_content))
modifed_md5, _ := calculateMD5(path)
file_index++
current_index := file_index
fmt.Printf("%d.【%s】 修改md5成功:[%s]=>[%s]\n", current_index, info.Name(), md5, modifed_md5)
}
return nil
}
func calculateMD5(filePath string) (string, error) {
file, err := os.Open(filePath)
if err != nil {
return "", err
}
defer file.Close()
hash := md5.New()
_, err = io.Copy(hash, file)
if err != nil {
return "", err
}
return hex.EncodeToString(hash.Sum(nil)), nil
}
func appendFileToChar(filepath string, bytes []byte) bool {
f, err := os.OpenFile(filepath, os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
panic(err)
}
defer f.Close()
_, err = f.Write(bytes)
if err != nil {
panic(err)
} else {
return true
}
}
func init() {
flag.StringVar(&start_path, "p", "", "遍历修改起始路径(默认为当前路径)")
flag.StringVar(&append_content, "s", "#123", "在末尾添加的字符(默认为#123)")
flag.Parse()
if start_path == "" {
dir, _ := os.Getwd()
start_path = dir
} else {
path, err := filepath.Abs(start_path)
if err != nil {
panic("提供的路径错误")
}
start_path = path
}
fmt.Println("起始路径:" + start_path)
var is_next string
for {
fmt.Print("是否确认执行?[Y/n]:")
fmt.Scanln(&is_next)
is_next = strings.ToLower(is_next)
if is_next == "n" || is_next == "no" {
fmt.Println("bye~")
os.Exit(0)
} else if is_next == "y" || is_next == "yes" {
break
}
fmt.Println("指令错误,请重新输入~")
}
}
func outEndInfo() {
fmt.Printf("成功处理[%d]个文件,失败处理[%d]个文件\n", success_count, fail_count)
}
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Printf("程序执行错误,%#v\n", err)
}
}()
defer outEndInfo()
defer fmt.Print("程序执行完毕,")
go func() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill)
<-c
fmt.Print("用户手动退出,")
outEndInfo()
os.Exit(0)
}()
fmt.Println("开始运行~")
startTime := time.Now()
// filepath.Walk(start_path, visit)
var wg sync.WaitGroup
filepath.Walk(start_path, func(path string, info fs.FileInfo, err error) error {
wg.Add(1)
go func() {
defer wg.Done()
visit(path, info, err)
}()
return nil
})
wg.Wait()
elapsedTime := time.Since(startTime) / time.Millisecond
fmt.Printf("执行耗时:%dms\n", elapsedTime)
}
测试
go build -o md5_tool main.go
[root@10-41-68-179 ~]# ./md5_tool -h
Usage of ./md5_tool:
-p string
遍历修改起始路径(默认为当前路径)
-s string
在末尾添加的字符(默认为#123) (default "#123")
[root@10-41-68-179 ~]# ./md5_tool -p "/root/res"
起始路径:/root/res
是否确认执行?[Y/n]:y
开始运行~
1.【{08THNQU8{)VP161D@UQWO9.jpg】 修改md5成功:[2b38e20c688916e19d162af511c58345]=>[03a2476efca2eea01c89fa260ec9d63a]
2.【0@$[76`4}}8@%QOIZATIF74.jpg】 修改md5成功:[f04ca4058192d878d9fdf88f4418571e]=>[4fc88cdcab77d444c52a6b06fcf0950f]
3.【1(T}S[XO2Q~9O1{~2XR((OV.jpg】 修改md5成功:[b14c972d5325f294a9593b0e846149e6]=>[ad519f72fdcede4eae9a8810cd49fbc0]
4.【1.mp3】 修改md5成功:[3b2b156112fa3a6bb0485b6dc1b970dd]=>[9f0bd8dea31e5d761c03fceab17f0de3]
5.【2WH%[_3KG{`[)YBNUG}WZFH.jpg】 修改md5成功:[026f4f23d99ef677f49c0e6b94419b7e]=>[7be4f4bdc2cf42ab3d3127442d924125]
6.【3AQPA%UXO6UE4J(I9%(H$Q2.jpg】 修改md5成功:[e31ba5712ebcf6339e1b036dd33ab112]=>[c7de16076186774f46f61a6939b8e5c8]
7.【5EBVQFC5LA1GCYQ$D`32ZBT.jpg】 修改md5成功:[a5b53e88e3d3bf8e2b2ecbf39458acd5]=>[a892d250744a7259fbc71e5f0f51da43]
8.【5WALP~UD$~X3[KA)9E155SA.jpg】 修改md5成功:[05d0cc88eeac48ebea0a69422ad0574d]=>[da5a0979c002d11913c24f16f20db10f]
9.【89M]BWGW)T6H}K]T@TDE8XI.jpg】 修改md5成功:[b867c9791f475e2837f7939355e69088]=>[80f04a04533585cde809722334f57a83]
10.【I)4{CG4UTNO](MH8RIDO243.jpg】 修改md5成功:[f2bb14fb9df53b20ebd89a5dc4468916]=>[5e7a002ee05745a57272ee99aa48b6b2]
11.【IFZ3U[CA}F0~[AWI5QC`X[7.jpg】 修改md5成功:[e24df4c0f7417ee2f3fd80401b391a3a]=>[37dbb840c4daf1eec175f79870442e13]
12.【W}EOFF(F9UNTY82JR}1`VWM.jpg】 修改md5成功:[6006b8f9c037039d33f4fe2c04deb6a5]=>[40927f50d5b184cfad6ae5dc54b4a967]
13.【XH@A2T51~DVW[ASWLB%7DQL.jpg】 修改md5成功:[513024a6ac8a630d637e6adefe716f9d]=>[b9f3aa902fe331c2f33352be61c5f969]
14.【YZCQKWSTBFE85}`O4@A]{{R.jpg】 修改md5成功:[b252809888fcd8deef3f9a8e0da5f5cb]=>[a600551702f1ee297a0a6cde2f4fc993]
15.【][L@ECRR%QH`MQTV[AM}`RT.jpg】 修改md5成功:[9e35ed2d1fa05b74ba98886b8e9b20d8]=>[42d96dc1f963242c992e0164dfca07af]
16.【]{%AF}5BMY)(BGCX8`Y`AKL.jpg】 修改md5成功:[3e47116e26860b76026cf5b75fc2839c]=>[7321c5f7688735d936ae747c1a870813]
17.【1.mp4】 修改md5成功:[431da34a9abd1d92f052ee850b421133]=>[f5d23bacf6404b0838b6b9ec24f1f42b]
执行耗时:24ms
程序执行完毕,成功处理[17]个文件,失败处理[0]个文件
仓库
参考链接
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
紧追大佬的步伐!
借鉴的成品