Golang中MD5哈希函数的使用与实现

Golang中MD5哈希函数的使用与实现 我是Go语言和编程的新手,这可能有点超出我的能力范围,但无论如何我还是要尝试一下。

我正在尝试实现一个函数,从视频文件开始,通过获取视频文件的前64KB和后64KB数据,将它们组合在一起并生成这些数据(共128KB)的MD5哈希值。

在谷歌的帮助下,我已经完成了MD5哈希函数的部分,但我现在难以实现的是如何"获取"文件的前64KB和后64KB数据,然后将这些片段"连接"在一起。

在一个Go语言的Discord群组中,有人提示我查看os包中的Seek()函数:

func main() {
testFile := os.Args[1]
var offset int64 = 64 * 1024 //64Kb
var whence int = 0           //starting from the beginning of the file
file, err := os.Open(testFile)
if err != nil {
	fmt.Println(err)
}

newPosition, err := file.Seek(offset, whence)
if err != nil {
	fmt.Println(err)
}

fmt.Println("Moved to new position: ", newPosition)

newPosition返回一个int64,我需要写入一个新的写入器吗?

先谢谢了


更多关于Golang中MD5哈希函数的使用与实现的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中MD5哈希函数的使用与实现的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go语言中处理文件的部分读取和MD5哈希生成是一个常见的需求。我来详细解释如何实现获取文件前64KB和后64KB数据并计算MD5哈希值。

首先,你需要使用os.Open()打开文件,然后使用Seek()来定位到文件的不同位置进行读取。以下是完整的实现示例:

package main

import (
	"crypto/md5"
	"fmt"
	"io"
	"os"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Usage: go run main.go <filename>")
		return
	}

	filename := os.Args[1]
	
	// 打开文件
	file, err := os.Open(filename)
	if err != nil {
		fmt.Printf("Error opening file: %v\n", err)
		return
	}
	defer file.Close()

	// 获取文件信息以确定文件大小
	fileInfo, err := file.Stat()
	if err != nil {
		fmt.Printf("Error getting file info: %v\n", err)
		return
	}

	fileSize := fileInfo.Size()
	chunkSize := int64(64 * 1024) // 64KB

	// 如果文件小于128KB,直接读取整个文件
	if fileSize <= chunkSize*2 {
		data := make([]byte, fileSize)
		_, err = file.Read(data)
		if err != nil {
			fmt.Printf("Error reading file: %v\n", err)
			return
		}
		
		hash := md5.Sum(data)
		fmt.Printf("MD5 Hash: %x\n", hash)
		return
	}

	// 读取前64KB
	firstChunk := make([]byte, chunkSize)
	_, err = file.Read(firstChunk)
	if err != nil {
		fmt.Printf("Error reading first chunk: %v\n", err)
		return
	}

	// 定位到文件末尾前64KB的位置
	_, err = file.Seek(-chunkSize, io.SeekEnd)
	if err != nil {
		fmt.Printf("Error seeking to end: %v\n", err)
		return
	}

	// 读取后64KB
	lastChunk := make([]byte, chunkSize)
	_, err = file.Read(lastChunk)
	if err != nil {
		fmt.Printf("Error reading last chunk: %v\n", err)
		return
	}

	// 合并两个数据块
	combinedData := append(firstChunk, lastChunk...)

	// 计算MD5哈希
	hash := md5.Sum(combinedData)
	fmt.Printf("MD5 Hash: %x\n", hash)
}

这里还有一个更简洁的版本,使用io.CopyN来处理读取:

package main

import (
	"crypto/md5"
	"fmt"
	"io"
	"os"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Usage: go run main.go <filename>")
		return
	}

	filename := os.Args[1]
	
	file, err := os.Open(filename)
	if err != nil {
		fmt.Printf("Error opening file: %v\n", err)
		return
	}
	defer file.Close()

	fileInfo, err := file.Stat()
	if err != nil {
		fmt.Printf("Error getting file info: %v\n", err)
		return
	}

	fileSize := fileInfo.Size()
	chunkSize := int64(64 * 1024)

	// 创建MD5哈希器
	hasher := md5.New()

	// 读取并写入前64KB到哈希器
	_, err = io.CopyN(hasher, file, chunkSize)
	if err != nil && err != io.EOF {
		fmt.Printf("Error reading first chunk: %v\n", err)
		return
	}

	// 如果文件足够大,读取后64KB
	if fileSize > chunkSize {
		// 定位到文件末尾前64KB
		_, err = file.Seek(-chunkSize, io.SeekEnd)
		if err != nil {
			fmt.Printf("Error seeking to end: %v\n", err)
			return
		}

		// 读取并写入后64KB到哈希器
		_, err = io.CopyN(hasher, file, chunkSize)
		if err != nil && err != io.EOF {
			fmt.Printf("Error reading last chunk: %v\n", err)
			return
		}
	}

	// 获取最终的MD5哈希值
	hash := hasher.Sum(nil)
	fmt.Printf("MD5 Hash: %x\n", hash)
}

关于你的代码中的问题:

  • file.Seek()返回的新位置是正确的,你不需要新的写入器
  • 使用Seek()后,后续的Read()操作会从新的位置开始读取
  • 对于从文件末尾定位,使用io.SeekEnd常量作为whence参数,配合负的偏移量

这两种方法都能实现你的需求,第二种方法更高效,因为它直接在读取过程中计算哈希,避免了额外的内存分配。

回到顶部