文件分割
分片上传需要先将文件分割为小块[]byte
//移动指针到开头
m.File.Seek(0, 0)
// 切片 每次上传5M
fileChunk := 5 * (1 << 20)
// 文件分割 多少份
totalPartsNum := uint64(math.Ceil(float64(m.Size) / float64(fileChunk)))
// 根据分割文件数创建channel
var ch = make(chan error, totalPartsNum)
for i := uint64(0); i < totalPartsNum; i++ {
// 计算本次上传 文件大小
partSize := int(math.Min(float64(fileChunk), float64(m.Size-int64(i*uint64(fileChunk)))))
// 创建本次上传的[]byte
partBuffer := make([]byte, partSize)
// 将文件读取到[]byte 因为File.Read读取后指针停留在最后读取的位置,所以下次直接读取会接着上次的继续读取
m.File.Read(partBuffer)
// 使用使用携程一次性上传
go m.doVideoUpload(partBuffer, partSize, int(totalPartsNum), int(i), ch)
}
for v := 0; v < int(totalPartsNum); v++ {
err := <-ch
if err != nil {
return err
}
}
使用携程将全部分片上传至远端
func (m *MPUploadVideo) doVideoUpload(FileBuff []byte, partSize int, chunks int, chunk int, ch chan error) {
var err error
defer func() {
ch <- err
}()
Url := "https://*/uploadpart"
client := &http.Client{Timeout: 120 * time.Second}
urlValues := url.Values{}
urlValues.Add("name", m.Filename)
urlValues.Add("type", "video/mp4")
urlValues.Add("lastModifiedDate", time.Now().Format("Mon Jan 02 2006 15:04:05 GMT +0800")+"中国标准时间")
urlValues.Add("size", strconv.Itoa(partSize))
urlValues.Add("partnum", strconv.Itoa(chunk+1))
urlValues.Add("chunks", strconv.Itoa(chunks))
urlValues.Add("chunk", strconv.Itoa(chunk))
urlValues.Add("filename", m.VideoUploadInfo.FileName)
urlValues.Add("ukey", m.VideoUploadInfo.Ukey)
mediaArg := MediaArg{}
mediaArg.Px = []px{
{
MinW: m.FileInfo.Width,
MaxW: m.FileInfo.Width,
MinH: m.FileInfo.Height,
MaxH: m.FileInfo.Height,
},
}
mediaArg.Size.Min = partSize
mediaArg.Size.Max = partSize
mediaArg.Duration.Max = int(m.FileInfo.Duration)
mediaArg.Duration.Min = int(m.FileInfo.Duration)
mediaArg.Profile = "High"
mediaArg.BitRate = 1228800
mediaArgStr, _ := json.Marshal(mediaArg)
urlValues.Add("media_arg", string(mediaArgStr))
UrlParam := urlValues.Encode()
req, _ := http.NewRequest("POST", Url+"?"+UrlParam, bytes.NewReader(FileBuff))
req.Header.Set("content-sha1", utils.GetBytesSha1(FileBuff))
req.Header.Set("x-arguments", m.XArguments)
req.Header.Set("Content-Type", "application/octet-stream")
resp, err := client.Do(req)
if err != nil {
return
}
//
body, _ := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
var resDoVidoeUpload ResDoVidoeUpload
unmarshal1Err := json.Unmarshal([]byte(body), &resDoVidoeUpload)
if unmarshal1Err != nil {
err = errors.New("上传视频:失败")
return
}
if resDoVidoeUpload.Code != 0 {
err = errors.New("上传视频:失败,msg:" + resDoVidoeUpload.Msg)
return
}
m.PartShas = append(m.PartShas, FinishPartsList{
PartNum: chunk + 1,
PartSha: resDoVidoeUpload.PartSha,
})
return
}