实现文件秒传

Posted 旧时星空

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现文件秒传相关的知识,希望对你有一定的参考价值。

实现文件秒传

文件的校验值计算

校验算法类型 校验码长度

1.CRC 4/8字节 计算效率高但安全性较低 传输数据的校验

2.MD5 16个字节 中等 文件校验和数据签名

3.SHA1 20个字节 安全性高 文件校验和数据签名

秒传原理

场景

1.用户上传

2.离线下载

3.好友分享

关键点

1.文件的Hash值(MD5,Sha1)

每次文件上传到云存储服务,会自动计算文件的HASH值,下一次用户上传,只要Hash值相同就可以省区重复上传,客户端计算文件Hash值传到云端进行对比才可以实现秒传

2.用户文件的关联

建立唯一文件表用于存储唯一的文件的信息,而用户文件表存储每个用户的文件的信息,包括重复文件

文件秒传服务架构

如图

1.用户上传文件到上传server

2.上传server将文件存储到本地

3.调用Hash计算文件Hash值

4.将文件信息存储到唯一文件表

5.将文件信息关联到用户文件表

如果计算出文件Hash值比对成功则减少上传实现秒传

用户文件表结构

在db/下创建db/userFile,并创建用户文件结构体和用户文件表的更新

import (
	mydb "rgo/src/db/mysql"
	"time"
)

//用户文件表的结构体
type UserFile struct
	UserName string
	FileHash string
	FileName string
	FileSize int64
	UploadAt string
	LastUpdated string

//更新用户文件表
func OnUserFileUploadFinished(username,filehash,filename string,filesize int64)bool
	stmt,err:=mydb.DBConn().Prepare("" +
		"insert ignore into tbl_user_file(`user_name`,`file_sha1`,`file_name`,"+
		"`file_size`,`upload_at`)values(?,?,?,?,?)")
	if err!=nil
		return false
	
	defer stmt.Close()
	_,err=stmt.Exec(username,filehash,filename,filesize,time.Now())
	if err!=nil
		return false
	
	return true

在handler/handler.go的UploadHandler中修改

//更新用户文件表记录
		r.ParseForm()
		username := r.Form.Get("username")
		suc := dblayer.OnUserFileUploadFinished(username, fileMeta.FileShal,
			fileMeta.FileName, fileMeta.FileSize)
		if suc 
			http.Redirect(w, r, "/file/upload/suc", http.StatusFound)
		 else 
			w.Write([]byte("Upload Failed"))
		

db/userFile下创建函数

//批量获取用户文件信息
func QueryUserFileMetas(username string,limit int)([]UserFile,error)
	stmt,err:=mydb.DBConn().Prepare(
		"select file_sha1,file_name,file_size,upload_at,last_update from"+
			"tbl_user_file where user_name=? limit ?")
	if err!=nil
		return nil,err
	
	defer stmt.Close()
	rows,err:=stmt.Query(username,limit)
	if err!=nil
		return nil,err
	
	var userFiles []UserFile
	for rows.Next()//从数据库查找的表中将文件信息复制到[]UserFile作为返回
		ufile:=UserFile
		err=rows.Scan(&ufile.FileHash,&ufile.FileName,&ufile.FileSize,
			&ufile.UploadAt,&ufile.LastUpdated)
		if err!=nil
			fmt.Println(err.Error())
			break
		
		userFiles=append(userFiles,ufile)
	
	return userFiles,nil

在handler/handler.go修改接口

//查询批量的文件元信息
func FileQueryHandler(w http.ResponseWriter,r*http.Request)
	r.ParseForm()
	limitCnt,_:=strconv.Atoi(r.Form.Get("limit"))
	username:=r.Form.Get("username")
	userFiles,err:=dblayer.QueryUserFileMetas(username,limitCnt)
	if err!=nil
		w.WriteHeader(http.StatusInternalServerError)
		return
	
	data,err:=json.Marshal(userFiles)
	if err!=nil
		w.WriteHeader(http.StatusInternalServerError)
		return
	
	w.Write(data)

修改后效果,可以显示文件Hash值,文件名等

在handler/handler.go中编写

//尝试秒传接口
func TryFastUploadHandler(w http.ResponseWriter,r*http.Request)
	r.ParseForm()
	//1.解析请求参数
	username:=r.Form.Get("username")
	filehash:=r.Form.Get("filehash")
	filename:=r.Form.Get("filename")
	filesize,_:=strconv.Atoi(r.Form.Get("filesize"))
	//从文件表中查询相同hash文件记录
    fileMeta,err:=meta.GetFileMetaDB(filehash)
    if err!=nil
    	fmt.Println(err.Error())
    	w.WriteHeader(http.StatusInternalServerError)
    	return
	
	//查找不到记录则返回秒传失败
     if fileMeta==nil
     	resp:=util.RespMsg
     		Code:-1,
     		Msg:"秒传失败,请访问普通上传接口",
		
		w.Write(resp.JSONBytes())
     	return
	 
	//上传文过件则将文件信息写入用户文件表,返回成功
	suc:=dblayer.OnUserFileUploadFinished(username,filehash,filename,int64(filesize))
	if suc
		resp:=util.RespMsg
			Code:0,
			Msg:"秒传成功",
		
		w.Write(resp.JSONBytes())
		return
	else
		resp:=util.RespMsg
			Code:-2,
			Msg:"秒传失败,请稍后重试",
		
		w.Write(resp.JSONBytes())
		return
	

以上是关于实现文件秒传的主要内容,如果未能解决你的问题,请参考以下文章

实现文件秒传

实现文件秒传

实现文件秒传

前端 + 后端 实现分片上传(断点续传/极速秒传)

大文件分片上传,断点续传,秒传 实现

如何实现大文件上传:秒传断点续传分片上传