当前位置:网站首页>分布式文件存储——文件秒传
分布式文件存储——文件秒传
2022-08-08 21:09:00 【~庞贝】
实现文件秒传
文件的校验值计算
校验算法类型 校验码长度
1.CRC 4/8字节 计算效率高但安全性较低 传输数据的校验
2.MD5 16个字节 中等 文件校验和数据签名
3.SHA1 20个字节 安全性高 文件校验和数据签名
场景
1.用户上传
2.离线下载
3.好友分享
关键点
1.文件的Hash值(MD5,Sha1)
每次文件上传到云存储服务,会自动计算文件的HASH值,下一次用户上传,只要Hash值相同就可以省区重复上传,客户端计算文件Hash值传到云端进行对比才可以实现秒传
2.用户文件的关联
建立唯一文件表用于存储唯一的文件的信息,而用户文件表存储每个用户的文件的信息,包括重复文件
文件秒传服务架构
如图
- 用户上传文件到上传server
- 上传server将文件存储到本地
- 调用Hash计算文件Hash值
- 将文件信息存储到唯一文件表
- 将文件信息关联到用户文件表
如果计算出文件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)
}
在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
}
}
边栏推荐
猜你喜欢
随机推荐
修改浏览器滚动条样式
【访问本地项目,localhosthost可以,本地ip不可以】
目标检测论文 Precise detection of Chinese characters in historical documents with DRL
编译原理——LR(1)分析程序(C#)
Iterative version of preorder traversal, inorder traversal, and postorder traversal of binary tree
二叉树前序遍历、中序遍历、后序遍历的迭代版
GeoServer入门学习:04-发布Shapfile地图数据
新规划|广州都市圈将以广佛为核心,广佛将有18条地铁相连通
- project experience 】 【 conservation projects
波动数列,简易AC代码,详细讲解。
【导出PDF-项目应用】
小程序——切割字符串
究竟什么才是“云计算” | 科普好文
sudo控制用户权限实战操作
ES6新特性let和const
keras调用load_model时报错ValueError: Unknown layer:*解决办法
并发和并行——从线程,线程池到任务
Property or method “XXX“ is not defined on the instance but referenced during render.
day3 Feign远程调用
ssh 登录connectction reset by peer