<input type="file">
<script>
let fl = document.querySelector('input')
let SIZE = 20 * 1024 * 1024//文件分片界限是20MB
fl.onchange = function() {
let file = fl.files[0]
let chunks = [], start = 0, end = SIZE
if(file.size >SIZE) {
let m = Math.ceil(file.size / SIZE)//需要分成多少片
while(m--) {
let chunk = file.slice(start, end) //对文件进行分片
chunks.push(chunk)//记录每次分片的文件
start = end
end += SIZE
if(end >file.size) end = file.size
}
//上传所有的分片文件
} else {
//小于分片界限的文件直接上传
}
}
</script>
在日常文件处理这一块,我们经常会有大文件处理的需求,这个文件有可能有100M以上,甚至更高。针对这种情况,如果直接上传到seaweedfs上面,受制于网络,服务器情况,单个文件过大,稳定性就会卖绝大打折扣。在查看了seaweedfs之后, Large-File-Handling ( https://github.com/chrislusf/seaweedfs/wiki/Large-File-Handling ).仔细阅读之中扒姿后,大概意思就是。seaweedfs的高可用是建立在处理小文件的前提下,因为文件会加载到seaweedfs的内存之中。在文件拆分这一块,内置是提供了filer这个服务来处理,它会自动处理这个问题。以过分析,我果断放弃,就像我对DB的理解一样,把数据存储搞定就行了。中间件就专注做好本职内的事情。所以我转向了另外一种解决办法,改为由客户端自行处理。我们可以根据实际情况,调整单个此掘包的大小,最好控制在10M以内,当然做成可配置是更好。然后把每个文件的信息整理成一个json对象,并命名为Manifest,告诉seaweedfs,这个大文件是由1,2,3。。。。这几个文件合并而成。详情请参考 https://github.com/chrislusf/seaweedfs/blob/master/weed/operation/chunked_file.go#L24
因为是go写的,大家看着可能有点不太习惯。我整理了java的模板,如下:
文件明细:ChunkInfo
fid:产生的唯一文件编码(7,169aba906a)一定是带逗号,具体这个编码的规则,大家去查看我之前写的 https://www.jianshu.com/p/32239852d984 。访问文件地址,http://127.0.0.1:9081/7/169aba906a/test1.zip
offset:文件读取的起始位置,如果是第一个文件就是0,如果是下一个文件,这个值就是上一个文件的结束位置
size:当前文件大小,以字节为单位
批量文件集合:ChunkManifest
name:新的文件名称
mine:文件类型,可以参考httpclient
size:合并之后的总文件大小,其实就是所有拆分文件的总合
chunks:上面ChunkInfo的集合
现在给一个实际的对象,大家看起来会更有感触:{
"name" : "allin.zip",
"mine" : "zip",
"size" : 127646446,
"chunks" : [ {
"fid" : "7/169aba906a",
"offset" : 0,
"size" : 52428800
}, {
"fid" : "4/177d5cadcc",
"offset" : 52428801,
"size" : 52428800
}, {
"fid" : "3/18f0e181ff",
"offset" : 104857601,
"size" : 22788846
} ]
}
这个对象整好之后,通过httpclient,走一般的seaweedfs文件上传流程,拿到ID,再把这个对象发送出去,成功之后就可以通过新的ID来访问这个合并之后的文件了。
正常情况下,一般都是在长传完成后,在服务器直接保存。?
1
2
3
4
5
6
7
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain"
//保存文件
context.Request.Files[0].SaveAs(context.Server.MapPath("~/1/" + context.Request.Files[0].FileName))
context.Response.Write("Hello World")
}
最近项目中用百度开源的上传组件webuploader,官方介绍昌大销webuploader支持分片上传。具体webuploader的使用方法见官网http://fex.baidu.com/webuploader/。
?
1
2
3
4
5
6
7
8
9
10
11
12
var uploader = WebUploader.create({
auto: true,
swf:'/webuploader/Uploader.swf',
// 文件接收服务端。
server: '/Uploader.ashx',
// 内部根据当前运行是创建,可能是input元耐游素,也可能是flash.
pick: '#filePicker',
chunked: true,//开启分片上传
threads: 1,//上传并发数
//由于Http的无状态特征,在往服务器发送数据过程传递一个进入当前页面是生成的GUID作为标示
formData: {guid:"<%=Guid.NewGuid().ToString()%>"}
})
webuploader的分片上传是把文件分成若干份,然后向你定义的文件接收端post数据,如果上传的文仿卖件大于分片的尺寸,就会进行分片,然后会在post的数据中添加两个form元素chunk和chunks,前者标示当前分片在上传分片中的顺序(从0开始),后者代表总分片数。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)