AI智能
改变未来

大文件分片上传的大概思路(go语言)


前端代码

下面代码为

上传页

<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Document</title></head><body><h2>Index</h2><div id=\"uploader\" class=\"wu-example\"><!--用来存放文件信息--><div class=\"filename\"></div><div class=\"state\"></div><!-- <div class=\"progress\"><div class=\"progress-bar progress-bar-info progress-bar-striped active\" role=\"progressbar\" aria-valuenow=\"40\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"width: 0%\"><span class=\"sr-only\">40% Complete (success)</span></div></div> --><div class=\"btns\"><div id=\"picker\">选择文件</div><button id=\"ctlBtn\" class=\"btn btn-default\">开始上传</button><button id=\"pause\" class=\"btn btn-danger\">暂停上传</button></div></div><script src=\"./static/jquery-3.3.1/jquery-3.3.1.min.js\"></script><script type=\"text/javascript\">$(function () {var GUID = WebUploader.Base.guid();//一个GUIDvar uploader = WebUploader.create({swf: \'./static/webuploader/Uploader.swf\',server: \'http://47.103.209.62:8080/upload/run\',pick: \'#picker\',resize: false,chunked: true,//开始分片上传chunkSize: 2048000,//每一片的大小formData: {guid: GUID //自定义参数,待会儿解释}});uploader.on(\'fileQueued\', function (file) {$(\"#uploader .filename\").html(\"文件名:\" + file.name);$(\"#uploader .state\").html(\'等待上传\');});uploader.on(\'uploadSuccess\', function (file, response) {$.post(\'http://47.103.209.62:8080/upload/complete\', { guid: GUID, fileName: file.name }, function (data) {$list.text(\'已上传\');});});uploader.on(\'uploadProgress\', function (file, percentage) {$(\"#uploader .progress-bar\").width(percentage * 100 + \'%\');console.log(percentage);});uploader.on(\'uploadSuccess\', function () {$(\"#uploader .progress-bar\").removeClass(\'progress-bar-striped\').removeClass(\'active\').removeClass(\'progress-bar-info\').addClass(\'progress-bar-success\');$(\"#uploader .state\").html(\"上传成功...\");});uploader.on(\'uploadError\', function () {$(\"#uploader .progress-bar\").removeClass(\'progress-bar-striped\').removeClass(\'active\').removeClass(\'progress-bar-info\').addClass(\'progress-bar-danger\');$(\"#uploader .state\").html(\"上传失败...\");});$(\"#ctlBtn\").click(function () {uploader.upload();$(\"#ctlBtn\").text(\"上传\");$(\'#ctlBtn\').attr(\'disabled\', \'disabled\');$(\"#uploader .progress-bar\").addClass(\'progress-bar-striped\').addClass(\'active\');$(\"#uploader .state\").html(\"上传中...\");});$(\'#pause\').click(function () {uploader.stop(true);$(\'#ctlBtn\').removeAttr(\'disabled\');$(\"#ctlBtn\").text(\"继续上传\");$(\"#uploader .state\").html(\"暂停中...\");$(\"#uploader .progress-bar\").removeClass(\'progress-bar-striped\').removeClass(\'active\');});});</script><link href=\"./static/webuploader/webuploader.css\" rel=\"stylesheet\" /><script src=\"./static/webuploader/webuploader.nolog.js\"></script></body></html>

后端代码

下面代码为

分片上传Api

//分片上传func (this *UploadController) RunMultipartUpload() {//参数data, err := this.GetParam()if err!=nil{code,_ := beego.AppConfig.Int(\"systemError\")this.ErrorJson(code, err.Error())}//接收字段名field_name := \"file\"//获取文件f, h, err := this.GetFile(field_name)if err != nil {code,_ := beego.AppConfig.Int(\"systemError\")this.ErrorJson(code, err.Error())}defer f.Close()//保存文件路径dir := \"static/multipart-upload/\"+data[\"guid\"].(string)//检查是否存在文件夹,没有则创建err = common.PathExists(dir)if err!=nil{code,_ := beego.AppConfig.Int(\"systemError\")this.ErrorJson(code, err.Error())}//文件后缀fileExt := path.Ext(h.Filename)//保存文件名fileName := data[\"chunk\"].(string) + fileExt//完整路径path := dir +\"/\"+ fileName//保存文件err = this.SaveToFile(field_name, path)if err!=nil{code,_ := beego.AppConfig.Int(\"systemError\")this.ErrorJson(code, err.Error())}//返回res := make(map[string]interface{})res[\"path\"] = paththis.SuccessJson(res)}

下面代码为

通知文件合并Api

//完成上传通知文件合并func (this *UploadController) CompleteUpload() {//参数data, err := this.GetParam2()if err!=nil{code,_ := beego.AppConfig.Int(\"systemError\")this.ErrorJson(code, err.Error())}t := time.Now()//分片目录srcPath := \"static/multipart-upload/\"+data[\"guid\"].(string)//合并后保存文件目录destPath := \"static/upload/\"+t.Format(\"2006-01-02\")//检查是否存在文件夹,没有则创建err = common.PathExists(destPath)if err!=nil{code,_ := beego.AppConfig.Int(\"systemError\")this.ErrorJson(code, err.Error())}//文件后缀fileSuffix := path.Ext(data[\"fileName\"].(string))//文件名fileName := data[\"guid\"].(string) + fileSuffix//命令行cmd := fmt.Sprintf(\"cd %s && ls | sort -n | xargs cat > $GOPATH/src/beegoApp/%s/%s\", srcPath, destPath, fileName)fmt.Print(cmd)//执行命令行mergeRes, err := common.ExecLinuxShell(cmd)if err!=nil{code,_ := beego.AppConfig.Int(\"systemError\")this.ErrorJson(code, err.Error())}//返回res := make(map[string]interface{})res[\"mergeRes\"] = mergeResthis.SuccessJson(res)}

总结

  前端使用

webuploader

插件的分片上传,把大文件分成一小片一小片上传到服务端(请求

分片上传Api

),服务端拿到分片文件先把他们临时存储起来,用前端传过来的

guid

参数作为分片临时目录名,

chunk

参数作为分片文件名以方便排序。

  最后上传完成前端会通知服务端合并文件(请求

通知文件合并Api

),服务端会把分片目录里面的所有分片文件通过文件名进行排序,并合并成为一个大文件。

  优点:文件是一点一点上传到服务端的,实现了断点续传,再也不用担心掉线问题了。

  缺点:前端要不断的请求上传接口,服务端压力大。

  PS:此代码只是一个大概的思路,一些功能,如前端的上传进度条,上传记录的持久化,文件合并之后删除分片目录等,都可以逐一完善,有什么建议都欢迎评论区讨论。

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » 大文件分片上传的大概思路(go语言)