md5 是什么

MD5 是消息摘要算法(Message Digest Algorithm 5)的缩写,它是一种常见的哈希函数,用于将任意长度的数据转换为固定长度(通常是128位)的哈希值。MD5 算法广泛用于计算数据的校验和、数字签名、数据完整性验证等方面。

MD5 算法对输入数据产生一个128位的哈希值,通常表示为一个32位的十六进制数。无论输入数据的大小,得到的哈希值长度都保持不变。它具有以下特点:

  1. 快速计算:MD5 算法的运算速度较快,适用于对大量数据进行校验和计算。
  2. 唯一性:不同的输入数据通常会生成不同的 MD5 哈希值,因此可以用于验证数据的完整性和唯一性。
  3. 不可逆性:无法从 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]个文件

仓库

md5-modify

参考链接

文章目录