




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第Go實(shí)現(xiàn)文件分片上傳Go語言在寫HTTP服務(wù)程序時(shí),會(huì)經(jīng)常用到文件上傳和文件下載,文件上傳和文件下載都可以用http包,默認(rèn)的功能基本上夠用了。http包支持文件下載的斷點(diǎn)續(xù)傳和進(jìn)度顯示,文件上傳貌似不支持?jǐn)帱c(diǎn)續(xù)傳,不知道是不是要web端來實(shí)現(xiàn)。
然后我自己配合web端實(shí)現(xiàn)了大文件分片上傳,來完成斷點(diǎn)續(xù)傳和進(jìn)度顯示的功能。
基本思想是,在web端將上傳的文件進(jìn)行分片處理,然后向服務(wù)端發(fā)送上傳請(qǐng)求(UploadRequest)包括文件名,MD5,文件大小,和文件總片數(shù)。
然后開始一片一片的上傳(Upload)。如果暫停了或者斷網(wǎng)失敗了,就記錄當(dāng)前上傳片的片數(shù),下一次上傳,重發(fā)UploadRequest,chunkPos為續(xù)傳位置片數(shù),然后從這個(gè)記錄的片數(shù)開始接著上傳(Upload)。在服務(wù)端,記錄首次請(qǐng)求的文件名,MD5,文件大小,文件總片數(shù),然后開始接收每一片,將每一個(gè)片保存為一個(gè)單獨(dú)的文件,在接收完最后一個(gè)片時(shí),將所有的分片份文件進(jìn)行合并。保存為對(duì)應(yīng)的文件名。最后再校驗(yàn)MD5碼。
對(duì)于不同用戶的請(qǐng)求,將文件上傳的信息存儲(chǔ)到session中,當(dāng)前文件上傳暫停后,上傳其它文件時(shí),向session增加新文件的信息。暫停后,接著上傳最開始的文件,則直接從session中取得該文件的信息,包括文件名,上傳到某一個(gè)片的信息等。
服務(wù)端實(shí)現(xiàn)代碼:
funcUploadRequest(whttp.ResponseWriter,r*http.Request){
log.WithFields(log.Fields{
"HTTP":r.Method,
"FUNC":"UploadRequest",
}).Info("HTTPREQUEST")
header:=w.Header()
header.Add("Content-Type","application/json")
/*sessionauthentication*/
sess:=session.GlobalSessions.SessionCheck(w,r)
ifsess==nil{
log.Error("sesscheckerror")
fmt.Fprintf(w,config.FmtStr,"3000","error","sessioncheckerror")
return
}
deferr.Body.Close()
con,_:=ioutil.ReadAll(r.Body)//獲取post的body數(shù)據(jù)
log.Info("UploadRequestjson:",string(con))
varuploadRequploadRequest
err:=json.Unmarshal([]byte(con),uploadReq)/*解析json字符串?dāng)?shù)據(jù)到結(jié)構(gòu)體中*/
iferr!=nil{
log.Error("jsonunmarshalerror")
fmt.Fprintf(w,config.FmtStr,"2000","error","jsonunmarshalerror")
return
}
switchuploadReq.Option{
case"reUploadFile":
{
sess.Set("currentFile",uploadReq)
err:=os.Remove("./tmp/"+uploadReq.FileName+"/"+uploadReq.FileName+"_"+uploadReq.ChunkPos)
iferr!=nil{
log.Error(err)
}
fmt.Fprintf(w,config.FmtStr,"1000","success","reuploadrequestsuccess")
}
case"uploadFile":
{
err=os.Mkdir("./tmp/"+uploadReq.FileName,0777)
iferr!=nil{
log.Info(err)
fmt.Fprintf(w,config.FmtStr,"3000","error","mkdirerror")
}else{
log.Infof("createdir%sok\r\n",uploadReq.FileName)
}
//文件上傳信息保存,保存到session中,用于分片續(xù)傳時(shí)使用
sess.Set(uploadReq.FileName,uploadReq)
sess.Set("currentFile",uploadReq)
fmt.Fprintf(w,config.FmtStr,"1000","success","uploadrequestsuccess")
}
case"uploadCancel":
{
err=os.RemoveAll("./tmp/"+uploadReq.FileName)
iferr!=nil{
log.Fatal(err)
}
sess.Delete(uploadReq.FileName)
fmt.Fprintf(w,config.FmtStr,"1000","success","uploadfilesuccess")
return
}
default:
{
fmt.Fprintf(w,config.FmtStr,"2000","error","uploadrequestoptionerror")
}
}
/*分片上傳功能實(shí)現(xiàn)*/
funcUpload(whttp.ResponseWriter,r*http.Request){
log.WithFields(log.Fields{
"HTTP":r.Method,
"FUNC":"Upload",
}).Info("HTTPREQUEST")
header:=w.Header()
header.Add("Content-Type","application/json")
/*sessionauthentication*/
sess:=globalSessions.SessionCheck(w,r)//session檢查的接口封裝
ifsess==nil{
log.Error("sessioncheckfailed")
fmt.Fprintf(w,config.FmtStr,"3000","error","sessioncheckfailed")
return
}
current_dir:=sess.Get("current_dir")
log.Info("currentdir:",current_dir)
up_dir:=sess.Get("up_dir")
log.Info("up_dir:",up_dir)
//varcurrent_dirstring="./river/test"
/*表單上傳文件*/
ifr.Method=="GET"{
crutime:=time.Now().Unix()
h:=md5.New()
io.WriteString(h,strconv.FormatInt(crutime,10))
token:=fmt.Sprintf("%x",h.Sum(nil))
t,_:=template.ParseFiles("upload.gtpl")
t.Execute(w,token)
}else{
r.ParseMultipartForm(3220)
file,_,err:=r.FormFile("uploadfile")
iferr!=nil{
log.Error(err)
return
}
deferfile.Close()
varuploadFileInfouploadRequest
uploadFileInfo=sess.Get("currentFile").(uploadRequest)
//fmt.Fprintf(w,"%v",sess.Get("fileName"))
varfileNamestring=uploadFileInfo.FileName+"_"+uploadFileInfo.ChunkPos
/*判斷上傳的文件是否已經(jīng)存在,可能發(fā)生同名的情況*/
log.Debug("fileName:",fileName)
_,err=os.Stat("./tmp/"+uploadFileInfo.FileName+"/"+fileName)
varf*os.File
iferr==nil{
fmt.Fprintf(w,config.FmtStr,"3000","error","fileisexsited")
return
}else{
f,err=os.OpenFile("./tmp/"+uploadFileInfo.FileName+"/"+fileName,os.O_WRONLY|os.O_CREATE,0666)//此處假設(shè)當(dāng)前目錄下已存在test目錄
}
deferf.Close()
iferr!=nil{
log.Error(err)
fmt.Fprintf(w,config.FmtStr,"3000","error","createfileerror")
return
}
io.Copy(f,file)//這里進(jìn)行大文件copy會(huì)導(dǎo)致內(nèi)存占用過大。一段時(shí)候后會(huì)進(jìn)行GC回收
log.Info("copyok")
//判斷是否單個(gè)文件是否上傳完畢,上傳完畢則合并文件到目標(biāo)文件夾
ifuploadFileInfo.ChunkPos==uploadFileInfo.ChunkNum{
f.Close()
_,err=os.Stat(current_dir.(string)+uploadFileInfo.FileName)
varfii*os.File
iferr==nil{
//如果已經(jīng)存在這個(gè)文件了,則在當(dāng)前文件名后增加日期
time:=time.Now().Format("2006-01-02_15-04-05")
log.Debug("Time:",time)
varfileName[]byte=[]byte(current_dir.(string)+uploadFileInfo.FileName)
varfileNameFinal[]byte=fileName
log.Debug("file_name:",string(fileName))
varpreFileName[]byte
varsufFileName[]byte
fori:=len(fileName)-1;ii--{
iffileName[i]=='.'{
preFileName=fileName[:i]//文件名前綴test
sufFileName=fileName[i:]//文件名后綴.txt
fileNameFinal=[]byte(string(preFileName)+"_"+time+string(sufFileName))
log.Info("fileNameFile:",fileNameFinal)
break
}
}
fii,err=os.OpenFile(string(fileNameFinal),os.O_WRONLY|os.O_CREATE,0777)//此處假設(shè)當(dāng)前目錄下已存在test目錄
}else{
fii,err=os.OpenFile(current_dir.(string)+uploadFileInfo.FileName,os.O_CREATE|os.O_WRONLY|os.O_APPEND,os.ModePerm)
}
deferfii.Close()
iferr!=nil{
log.Error(err)
fmt.Fprintf(w,config.FmtStr,"3000","error","Openobjectfileerror")
return
}
index,_:=strconv.Atoi(uploadFileInfo.ChunkNum)
fori:=1;i=index;i++{
f11,err:=os.OpenFile("./tmp/"+uploadFileInfo.FileName+"/"+uploadFileInfo.FileName+"_"+strconv.Itoa(int(i)),os.O_RDONLY,os.ModePerm)
iferr!=nil{
log.Error(err)
fmt.Fprintf(w,config.FmtStr,"3000","error","Openslicefileerror")
return
}
b,err:=ioutil.ReadAll(f11)
iferr!=nil{
log.Error(err)
fmt.Fprintf(w,config.FmtStr,"3000","error","ioutilreadallerror")
return
}
fii.Write(b)
f11.Close()
}
err=os.RemoveAll("./tmp/"+uploadFileInfo.FileName)
iferr!=nil{
log.Error(err)
}
sess.Delete(uploadFileInfo.FileName)
fii.Close()
ifuploadFileInfo.MD5==FileMD5(fii.Name()){
err:=os.Remove(current_dir.(string)+fii.Name())
iferr!=nil{
log.Error(err)
}
fmt.Fprintf(w,config.FmtStr,"3000","erro
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 鋼材公司的合同范本
- 委托轉(zhuǎn)租門面合同范本
- 2017租房協(xié)議合同范本
- 青少年讀本出版合同
- 新租賃廠房合同范本
- 入戶空間租房合同范本
- 公路承包開挖合同范本
- 混合型腸易激綜合征護(hù)理查房
- 成套電器銷售合同范本
- 2008租賃合同范本
- 英漢互譯單詞練習(xí)打印紙
- 四川JS-004竣工驗(yàn)收?qǐng)?bào)告
- 花卉栽植施工方案
- 水工閘門課件
- 水泥生產(chǎn)企業(yè)生產(chǎn)安全事故綜合應(yīng)急預(yù)案
- 全自動(dòng)血液細(xì)胞分析儀產(chǎn)品技術(shù)要求深圳邁瑞
- 找對(duì)英語學(xué)習(xí)方法的第一本書
- 安徽涵豐科技有限公司年產(chǎn)6000噸磷酸酯阻燃劑DOPO、4800噸磷酸酯阻燃劑DOPO衍生品、12000噸副產(chǎn)品鹽酸、38000噸聚合氯化鋁、20000噸固化劑項(xiàng)目環(huán)境影響報(bào)告書
- 《諾丁山》經(jīng)典臺(tái)詞
- 對(duì)鐵路機(jī)車乘務(wù)員規(guī)章培訓(xùn)的探討與實(shí)踐
- 臨床醫(yī)學(xué)實(shí)驗(yàn)室 儀器設(shè)備一覽表格模板
評(píng)論
0/150
提交評(píng)論