这里只写后端的代码,基本的思想就是,前端将文件分片,然后每次访问上传接口的时候,向后端传入参数:当前为第几块文件,和分片总数

下面直接贴代码吧,一些难懂的我大部分都加上注释了:

上传文件实体类:

看得出来,实体类中已经有很多我们需要的功能了,还有实用的属性。如MD5秒传的信息。

public class FileInf {

public FileInf(){}

public String id="";

public String pid="";

public String pidRoot="";

/**  * 表示当前项是否是一个文件夹项。    */

public boolean fdTask=false;

//   /// 是否是文件夹中的子文件  /// </summary>

public boolean fdChild=false;

/**  * 用户ID。与第三方系统整合使用。    */

public int uid=0;

/**  * 文件在本地电脑中的名称   */

public String nameLoc="";

/**  * 文件在服务器中的名称。   */

public String nameSvr="";

/**  * 文件在本地电脑中的完整路径。示例:D:\Soft\QQ2012.exe */

public String pathLoc="";

/**  * 文件在服务器中的完整路径。示例:F:\\ftp\\uer\\md5.exe     */

public String pathSvr="";

/**  * 文件在服务器中的相对路径。示例:/www/web/upload/md5.exe   */

public String pathRel="";

/**  * 文件MD5    */

public String md5="";

/**  * 数字化的文件长度。以字节为单位,示例:120125    */

public long lenLoc=0;

/**  * 格式化的文件尺寸。示例:10.03MB   */

public String sizeLoc="";

/**  * 文件续传位置。  */

public long offset=0;

/**  * 已上传大小。以字节为单位 */

public long lenSvr=0;

/**  * 已上传百分比。示例:10%  */

public String perSvr="0%";

public boolean complete=false;

public Date PostedTime = new Date();

public boolean deleted=false;

/**  * 是否已经扫描完毕,提供给大型文件夹使用,大型文件夹上传完毕后开始扫描。  */

public boolean scaned=false;

}

首先是文件数据接收逻辑,负责接收控件上传的文件块数据,然后写到服务器的文件中。控件已经提供了块的索引,大小,MD5和长度信息,我们可以根据需要来灵活进行处理,也可以将文件块的数据保存到分布式存储系统中。

<%

out.clear();

String uid             = request.getHeader("uid");//

String id              = request.getHeader("id");

String lenSvr      = request.getHeader("lenSvr");

String lenLoc      = request.getHeader("lenLoc");

String blockOffset = request.getHeader("blockOffset");

String blockSize   = request.getHeader("blockSize");

String blockIndex  = request.getHeader("blockIndex");

String blockMd5        = request.getHeader("blockMd5");

String complete        = request.getHeader("complete");

String pathSvr         = "";

//参数为空

if(  StringUtils.isBlank( uid )

|| StringUtils.isBlank( id )

|| StringUtils.isBlank( blockOffset ))

{

XDebug.Output("param is null");

return;

}

// Check that we have a file upload request

boolean isMultipart = ServletFileUpload.isMultipartContent(request);

FileItemFactory factory = new DiskFileItemFactory();

ServletFileUpload upload = new ServletFileUpload(factory);

List files = null;

try

{

files = upload.parseRequest(request);

}

catch (FileUploadException e)

{// 解析文件数据错误

out.println("read file data error:" + e.toString());

return;

}

FileItem rangeFile = null;

// 得到所有上传的文件

Iterator fileItr = files.iterator();

// 循环处理所有文件

while (fileItr.hasNext())

{

// 得到当前文件

rangeFile = (FileItem) fileItr.next();

if(StringUtils.equals( rangeFile.getFieldName(),"pathSvr"))

{

pathSvr = rangeFile.getString();

pathSvr = PathTool.url_decode(pathSvr);

}

}

boolean verify = false;

String msg = "";

String md5Svr = "";

long blockSizeSvr = rangeFile.getSize();

if(!StringUtils.isBlank(blockMd5))

{

md5Svr = Md5Tool.fileToMD5(rangeFile.getInputStream());

}

verify = Integer.parseInt(blockSize) == blockSizeSvr;

if(!verify)

{

msg = "block size error sizeSvr:" + blockSizeSvr + "sizeLoc:" + blockSize;

}

if(verify && !StringUtils.isBlank(blockMd5))

{

verify = md5Svr.equals(blockMd5);

if(!verify) msg = "block md5 error";

}

if(verify)

{

//保存文件块数据

FileBlockWriter res = new FileBlockWriter();

//仅第一块创建

if( Integer.parseInt(blockIndex)==1) res.CreateFile(pathSvr,Long.parseLong(lenLoc));

res.write( Long.parseLong(blockOffset),pathSvr,rangeFile);

up6_biz_event.file_post_block(id,Integer.parseInt(blockIndex));

JSONObject o = new JSONObject();

o.put("msg", "ok");

o.put("md5", md5Svr);

o.put("offset", blockOffset);//基于文件的块偏移位置

msg = o.toString();

}

rangeFile.delete();

out.write(msg);

%>

文件初始化部分

<%

out.clear();

WebBase web = new WebBase(pageContext);

String id     = web.queryString("id");

String md5         = web.queryString("md5");

String uid         = web.queryString("uid");

String lenLoc      = web.queryString("lenLoc");//数字化的文件大小。12021

String sizeLoc     = web.queryString("sizeLoc");//格式化的文件大小。10MB

String callback = web.queryString("callback");

String pathLoc     = web.queryString("pathLoc");

pathLoc            = PathTool.url_decode(pathLoc);

//参数为空

if ( StringUtils.isBlank(md5)

&& StringUtils.isBlank(uid)

&& StringUtils.isBlank(sizeLoc))

{

out.write(callback + "({\"value\":null})");

return;

}

FileInf fileSvr= new FileInf();

fileSvr.id = id;

fileSvr.fdChild = false;

fileSvr.uid = Integer.parseInt(uid);

fileSvr.nameLoc = PathTool.getName(pathLoc);

fileSvr.pathLoc = pathLoc;

fileSvr.lenLoc = Long.parseLong(lenLoc);

fileSvr.sizeLoc = sizeLoc;

fileSvr.deleted = false;

fileSvr.md5 = md5;

fileSvr.nameSvr = fileSvr.nameLoc;

//所有单个文件均以uuid/file方式存储

PathBuilderUuid pb = new PathBuilderUuid();

fileSvr.pathSvr = pb.genFile(fileSvr.uid,fileSvr);

fileSvr.pathSvr = fileSvr.pathSvr.replace("\\","/");

DBConfig cfg = new DBConfig();

DBFile db = cfg.db();

FileInf fileExist = new FileInf();

boolean exist = db.exist_file(md5,fileExist);

//数据库已存在相同文件,且有上传进度,则直接使用此信息

if(exist && fileExist.lenSvr > 1)

{

fileSvr.nameSvr             = fileExist.nameSvr;

fileSvr.pathSvr        = fileExist.pathSvr;

fileSvr.perSvr              = fileExist.perSvr;

fileSvr.lenSvr              = fileExist.lenSvr;

fileSvr.complete       = fileExist.complete;

db.Add(fileSvr);

//触发事件

up6_biz_event.file_create_same(fileSvr);

}//此文件不存在

else

{

db.Add(fileSvr);

//触发事件

up6_biz_event.file_create(fileSvr);

FileBlockWriter fr = new FileBlockWriter();

fr.CreateFile(fileSvr.pathSvr,fileSvr.lenLoc);

}

Gson gson = new Gson();

String json = gson.toJson(fileSvr);

json = URLEncoder.encode(json,"UTF-8");//编码,防止中文乱码

json = json.replace("+","%20");

json = callback + "({\"value\":\"" + json + "\"})";//返回jsonp格式数据。

out.write(json);%>

第一步:获取RandomAccessFile,随机访问文件类的对象

第二步:调用RandomAccessFile的getChannel()方法,打开文件通道 FileChannel,这块逻辑可以优化,如果以后有分布式存储需求,可以改为分布式存储,减轻单台服务器的压力。

public class FileBlockWriter {

public FileBlockWriter(){}

public void CreateFile(String pathSvr,long lenLoc)

{

try

{

File ps = new File(pathSvr);

PathTool.createDirectory(ps.getParent());

RandomAccessFile raf = new RandomAccessFile(pathSvr, "rw");

raf.setLength(lenLoc);//fix:以原始大小创建文件

raf.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

public void write(long offset,String pathSvr,FileItem block)

{

try

{

InputStream stream = block.getInputStream();

byte[] data = new byte[(int)block.getSize()];

stream.read(data);

stream.close();

RandomAccessFile raf = new RandomAccessFile(pathSvr,"rw");

raf.seek(offset);

raf.write(data);

raf.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

第三步:获取当前是第几个分块,计算文件的最后偏移量

第四步:获取当前文件分块的字节数组,用于获取文件字节长度

第五步:使用文件通道FileChannel类的 map()方法创建直接字节缓冲器  MappedByteBuffer

第六步:将分块的字节数组放入到当前位置的缓冲区内  mappedByteBuffer.put(byte[] b);

第七步:释放缓冲区

第八步:检查文件是否全部完成上传

文件夹扫描类

存储路径生成类

好了,到此就全部结束了,如果有疑问或批评,欢迎评论和私信,我们一起成长一起学习。

最后放一张实现的效果图

后端代码逻辑大部分是相同的,目前能够支持MySQL,Oracle,SQL。在使用前需要配置一下数据库,可以参考我写的这篇文章:http://blog.ncmem.com/wordpress/2019/08/07/java超大文件上传与下载/

使用webuploader实现分片上传的更多相关文章

  1. 【原创】MVC +WebUploader 实现分片上传大文件

    大文件的上传是我一直以来想学习的一个技术点,今天在项目闲暇之时,终于有机会自己尝试了一把,本文仅仅是个Demo,各种错误处理都么有,仅限于大家来学习思路. 参考博文:http://www.cnblog ...

  2. 用百度webuploader分片上传大文件

    一般在做文件上传的时候,都是通过客户端把要上传的文件上传到服务器,此时上传的文件都在服务器内存,如果上传的是视频等大文件,那么服务器内存就很紧张,而且一般我们都是用flash或者html5做异步上传, ...

  3. Webuploader 大文件分片上传

    百度Webuploader 大文件分片上传(.net接收)   前阵子要做个大文件上传的功能,找来找去发现Webuploader还不错,关于她的介绍我就不再赘述. 动手前,在园子里找到了一篇不错的分片 ...

  4. Vue2.0结合webuploader实现文件分片上传

    Vue项目中遇到了大文件分片上传的问题,之前用过webuploader,索性就把Vue2.0与webuploader结合起来使用,封装了一个vue的上传组件,使用起来也比较舒爽. 上传就上传吧,为什么 ...

  5. 30分钟玩转Net MVC 基于WebUploader的大文件分片上传、断网续传、秒传(文末附带demo下载)

    现在的项目开发基本上都用到了上传文件功能,或图片,或文档,或视频.我们常用的常规上传已经能够满足当前要求了, 然而有时会出现如下问题: 文件过大(比如1G以上),超出服务端的请求大小限制: 请求时间过 ...

  6. webuploader分片上传

    屁话不多说直接上主题; webuploader,sj(WebUploader 0.1.6)网上有下 powerUpload.js 自己写的基与楼上的插件 asp.net mvc/Api 实现效果: H ...

  7. 百度Webuploader 大文件分片上传(.net接收)

    前阵子要做个大文件上传的功能,找来找去发现Webuploader还不错,关于她的介绍我就不再赘述. 动手前,在园子里找到了一篇不错的分片上传的帖子,参考之后,踏出了第一步.此文记录我这次实践的点滴,仅 ...

  8. asp.net mvc+webuploader大文件分片上传

    首先是前端: var GUID = WebUploader.Base.guid();//一个GUID uploadereditsVideo = WebUploader.create({ // swf文 ...

  9. 视频大文件分片上传(使用webuploader插件)

    背景 公司做网盘系统,一直在调用图片服务器的接口上传图片,以前写的,以为简单改一改就可以用 最初要求 php 上传多种视频格式,支持大文件,并可以封面截图,时长统计 问题 1.上传到阿里云服务器,13 ...

随机推荐

  1. 20191125:Python中的上下文管理机制with

    20191125:with上下文管理 with是一个上下文管理器,用于执行代码块所需要的运行的时候的上下文入口和出口.上下文管理器的典型用法包括保存和还原各种全局状态,锁定和解锁资源,关闭打开的文件等 ...

  2. 04 IO流(二)——IO类的记忆方法、使用场景

    关于IO流以前写的PPT式笔记请跳转:https://blog.csdn.net/SCORPICAT/article/details/87975094#262___1451 IO流的主要结构 记忆方法 ...

  3. C/C++中vector与list的区别

    1.vector数据结构vector和数组类似,拥有一段连续的内存空间,并且起始地址不变.因此能高效的进行随机存取,时间复杂度为o(1);但因为内存空间是连续的,所以在进行插入和删除操作时,会造成内存 ...

  4. 软键盘 显示隐藏 测量高度 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  5. 记录MindSphere On Cloud Foundry的一次尝试过程

    试验背景: 开始时间:2019年12月11日 结束时间:2019年12月13日 自己编写一个后台程序,尝试推送到Cloud Foundry上,并开放从MindSphere以外访问的权限. 程序实现以下 ...

  6. 8. Java的运算符

    计算机的最基本用途之一就是执行数学运算,作为一门计算机语言,Java也提供了一套丰富的运算符来操纵变量. 我们把运算符具体分为:算数运算符,比较运算符,逻辑运算符,位运算符,赋值运算符,条件运算符,i ...

  7. Tomcat安装及环境配置

    欢迎任何形式的转载,但请务必注明出处. 本章内容 安装 环境变量入口 三个系统变量配置 测试安装配置是否成功 安装之前请安装jdk并进行环境配置(点击进入jdk教程) 一.安装 点击进入官网下载 二. ...

  8. zabbix推送内存监控单应用shell

    利用top方式获取指定第三方的内存使用率 #!/bin/bash process=$1 if [ ! -z $process ];then cd /zabbix/zabbix-agent/script ...

  9. OpenStack kilo版(7) 部署dashboard

    安装dashboard  root@controller:~# apt-get install openstack-dashboard  配置 /etc/openstack-dashboard/loc ...

  10. 分布式Hadoop和HBase整合

    环境: CentOS 6.6                hadoop-2.6.0            hbase-0.98.10.1 HBase1    192.168.1.4     Mast ...