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

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

上传文件实体类:

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

publicclassFileInf {

public FileInf(){}

publicStringid="";

publicStringpid="";

publicStringpidRoot="";

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

publicbooleanfdTask=false;

// /// 是否是文件夹中的子文件 ///

publicbooleanfdChild=false;

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

publicintuid=0;

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

publicStringnameLoc="";

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

publicStringnameSvr="";

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

publicStringpathLoc="";

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

publicStringpathSvr="";

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

publicStringpathRel="";

/** * 文件MD5 */

publicStringmd5="";

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

publiclonglenLoc=0;

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

publicStringsizeLoc="";

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

publiclongoffset=0;

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

publiclonglenSvr=0;

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

publicStringperSvr="0%";

publicbooleancomplete=false;

publicDatePostedTime = newDate();

publicbooleandeleted=false;

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

publicbooleanscaned=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超大文件上传与下载/

web uploader 上传大文件总结的更多相关文章

  1. web页面上传大文件有没有好的解决方案

    本人在2010年时使用swfupload为核心进行文件的批量上传的解决方案.见文章:WEB版一次选择多个文件进行批量上传(swfupload)的解决方案. 本人在2013年时使用plupload为核心 ...

  2. WEB上传大文件解决方案

    众所皆知,web上传大文件,一直是一个痛.上传文件大小限制,页面响应时间超时.这些都是web开发所必须直面的. 本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路.下面贴出简易 ...

  3. Web上传大文件的解决方案

    需求:项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在500M内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以501M来进行限制. 第一步: 前端修改 由于项目使用的是 ...

  4. WEB上传大文件

    众所皆知,web上传大文件,一直是一个痛.上传文件大小限制,页面响应时间超时.这些都是web开发所必须直面的. 本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路.下面贴出简易 ...

  5. 【Web应用】JAVA网络上传大文件报500错误

    问题描述 当通过 JAVA 网站上传大文件,会报 500 错误. 问题分析 因为 Azure 的 Java 网站都是基于 IIS 转发的,所以我们需要关注 IIS 的文件上传限制以及 requestT ...

  6. web上传大文件(>4G)有什么解决方案?

    众所皆知,web上传大文件,一直是一个痛.上传文件大小限制,页面响应时间超时.这些都是web开发所必须直面的. 本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路. 实现文件夹 ...

  7. ASP.NET 使用 plupload 上传大文件时出现“blob”文件的Bug

    最近在一个ASP.NET 项目中使用了plupload来上传文件,结果几天后客户发邮件说上传的文件不对,说是文件无法打开 在进入系统进行查看后发现上传的文件竟然没有后缀,经过一番测试发现如果文件上传的 ...

  8. java上传大文件解决方案

    需求:项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在10G内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以10G来进行限制. 第一步: 前端修改 由于项目使用的是BJ ...

  9. [Asp.net]Uploadify上传大文件,Http error 404 解决方案

    引言 之前使用Uploadify做了一个上传图片并预览的功能,今天在项目中,要使用该插件上传大文件.之前弄过上传图片的demo,就使用该demo进行测试.可以查看我的这篇文章:[Asp.net]Upl ...

随机推荐

  1. PADS软件

    最近学习PADS,搜集到的一些软件.之前一直在使用Altium designer,但是AD太占资源了,还有都说PADS比AD好. 下面是来自网上对主流PCB的介绍(原文:http://9mcu.com ...

  2. linux安装.net core3.0

    https://docs.microsoft.com/zh-cn/dotnet/core/install/linux-package-manager-centos7 更新资料库 sudo rpm -U ...

  3. 测开之路八十五:python处理csv文件

    写入csv文件 一:写入字典 二:写入普通数据 读取: 第一种:普通读取 第二种:读取csv并用namedtuple映射列名,类似于使用类的实例 第三种:字典形式 import csvfrom col ...

  4. Delphi中Tlist实例

    http://blog.163.com/jiandande3218@126/blog/static/74728469201132721428194/ Delphi中Tlist实例 2011-04-27 ...

  5. 使用eclipse制作war包方法 web项目打包到tomcat

    打开eclipse在左侧右击项目名选择“Export”   在导出画面点击 “Web”->“WAR file”点击“Next”   点击“Browse…”选择文件的导出位置,Target run ...

  6. PHP安装-centos7

    下载地址:https://www.php.net/downloads.php 1.wget下载php源码至/usr/local/src 下 wget https://www.php.net/distr ...

  7. Learn Python the hard way, ex40 字典,可爱的字典

    #!/usr/bin/python #coding:utf-8 cities ={'CA':'sf','MI':'dt','FL':'je'} #创建字典 cities['NY']='ny' #增加新 ...

  8. Python 学习笔记17 文本 - 读写

    在我们的编程过程中,我们经常需要对文件进行读写操作. 在Python中,对文本的读写非常的方便,只需要简单的几行代码就可以实现. 我们首先新建一个文本文件"Text.txt", 里 ...

  9. 洛谷 P1731 [NOI1999]生日蛋糕(搜索剪枝)

    题目链接 https://www.luogu.org/problemnew/show/P1731 解题思路 既然看不出什么特殊的算法,显然是搜索... dfs(u,v,s,r0,h0)分别表示: u为 ...

  10. BZOJ 1588 (treap)

    题面 传送门 分析 语文题,主要是如何理解最小波动值 设当前天的营业额为x,则最小波动值为min(x-最大的<=x的数,最小的>=x的数-x) 然后用Treap维护序列就可以了 时间复杂度 ...