golang下载文件并计算md5
今天遇到一个需求,需要从远程服务器下载文件,并对文件做一些其他处理(eg:计算MD5,计算sha256,计算sha1,并生成种子文件......)
中间遇到个文件,request.body 一旦被 md5.Write,sha256 再做 write 操作就无法从request.body中读取出来数据了。
......
resp, _ := client.Do(request)
var md5Hash := md5.New()
var shaHash := sha256.New()
md5Hash.Write(resp.Body)
shaHash.Write(resp.Body)
这种操作 shaHash.Write 就无法写入数据,生成的是0 byte的 sha256 的值。
解决这个问题,需要写一个结构体,实现 io.Reader 接口。然后在read的时候做处理。示例代码如下
type IoReader struct {
Reader io.ReadCloser
ReadBytes uint64 // 已经读取的字节数
LogBytes uint64 // 每次打日志的字节数
Md5 hash.Hash // md5生成
Sha256 hash.Hash // 生成sha256
}
func NewIoBodyReader(rc io.ReadCloser) *IoReader {
return &IoReader{
Reader: rc,
Md5: md5.New(),
Sha256: sha256.New(),
}
}
func (s *IoReader) Read(p []byte) (n int, err error) {
count, err := s.Reader.Read(p)
s.Md5.Write(p[:count])
s.Sha256.Write(p[:count])
s.ReadBytes += uint64(count)
s.LogBytes += uint64(count)
if s.LogBytes >= 1024 {
log.Printf("已经读取 %d 字节", s.ReadBytes)
s.LogBytes = 0
}
return count, err
}
使用上面的结构去写文件,eg:
file, _ := os.OpenFile("tmp.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
defer file.Close()
buf := make([]byte, 10240)
writer := bufio.NewWriter(file)
if _, err = io.CopyBuffer(writer, ioReader, buf); err != nil {
log.Printf("copy errr:%s", err.Error())
return
}
fmt.Printf("md5:%x\n", ioReader.Md5.Sum(nil))
writer.Flush()
完整示例:
func main(){
var (
url = "http://www.baidu.com"
data = map[string]interface{}{
"name": "light",
}
reader io.Reader
)
dataByte, _ := json.Marshal(data)
reader = bytes.NewReader(dataByte)
request, err := http.NewRequest("POST", url, reader)
request.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36")
client := &http.Client{}
client.Timeout = CallTimeOut
resp, err := client.Do(request)
if err != nil {
return
}
if request.Body != nil {
defer request.Body.Close()
}
defer resp.Body.Close()
ioReader := NewIoBodyReader(resp.Body)
file, _ := os.OpenFile("tmp.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
defer file.Close()
buf := make([]byte, 10240)
writer := bufio.NewWriter(file)
if _, err = io.CopyBuffer(writer, ioReader, buf); err != nil {
log.Printf("copy errr:%s", err.Error())
return
}
fmt.Printf("md5:%x\n", ioReader.Md5.Sum(nil))
fmt.Printf("md5:%x\n", ioReader.Sha256.Sum(nil))
writer.Flush()
}
可以看到打印出来的md5,和sha256,跟文件的一致。