Baidu WebUploader 前端文件上传组件的使用

简介

WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。在现代的浏览器里面能充分发挥HTML5的优势,同时又不摒弃主流IE浏览器,沿用原来的FLASH运行时,兼容IE6+,iOS 6+, android 4+。两套运行时,同样的调用方式,可供用户任意选用。 采用大文件分片并发上传,极大的提高了文件上传效率。

特点

分片、并发

分片与并发结合,将一个大文件分割成多块,并发上传,极大地提高大文件的上传速度。当网络问题导致传输错误时,只需要重传出错分片,而不是整个文件。另外分片传输能够更加实时的跟踪上传进度。

预览、压缩

支持常用图片格式jpg,jpeg,gif,bmp,png预览与压缩,节省网络数据传输。解析jpeg中的meta信息,对于各种orientation做了正确的处理,同时压缩后上传保留图片的所有原始meta数据。

多途径添加文件

支持文件多选,类型过滤,拖拽(文件&文件夹),图片粘贴功能。粘贴功能主要体现在当有图片数据在剪切板中时(截屏工具如QQ(Ctrl + ALT + A), 网页中右击图片点击复制),Ctrl + V便可添加此图片文件。

HTML5 & FLASH

兼容主流浏览器,接口一致,实现了两套运行时支持,用户无需关心内部用了什么内核。同时Flash部分没有做任何UI相关的工作,方便不关心Flash的用户扩展和自定义业务需求。

MD5秒传

当文件体积大、量比较多时,支持上传前做文件md5值验证,一致则可直接跳过。如果服务端与前端统一修改算法,取段md5,可大大提升验证性能,耗时在20ms左右。

易扩展、可拆分

采用可拆分机制,将各个功能独立成了小组件,可*搭配。采用AMD规范组织代码,清晰明了,方便高级玩家扩展。

下载

下载地址:https://github.com/fex-team/webuploader/releases

可以选择最新版进行下载。下载的压缩包中有如下文件。

Baidu WebUploader 前端文件上传组件的使用

├── Uploader.swf                      // SWF文件,当使用Flash运行时需要引入。

├── webuploader.js                    // 完全版本。
├── webuploader.min.js // min版本 ├── webuploader.nolog.js // 完全版本不带日志功能。
├── webuploader.nolog.min.js // min版本 ├── webuploader.flashonly.js // 只有Flash实现的版本。
├── webuploader.flashonly.min.js // min版本 ├── webuploader.html5only.js // 只有Html5实现的版本。
├── webuploader.html5only.min.js // min版本 ├── webuploader.withoutimage.js // 去除图片处理的版本,包括HTML5和FLASH.
└── webuploader.withoutimage.min.js // min版本

示例

具体文档可以直接参考官方网站的说明,这个使用说明还是很详细的,这里就不重复搬运了。

官网地址:http://fex.baidu.com/webuploader/doc/index.html

下面看一下我们项目中的实际应用。

前端代码

先引入相关js文件:

<script type="text/javascript" src="js/jquery-1.11.3.min.js"></script>
<script type="text/javascript" src="js/webuploader.nolog.js"></script>

页面引入相关控件:

<div id="uploadBtn" class="btn btn-upload">上传文件</div>
<div id="list" class="upload-box clearfix"></div>

前端js代码:

 //验证数组方法
Array.prototype.contains = function (obj) {
var i = this.length;
while (i--) {
if (this[i] === obj) {
return true;
}
}
return false;
} var arr_md5 = [];//加载页面时,将已上传成功的分片数组化
var chunks = 0;//分片总数量,用来上传成功以后校验分片文件总数
var repart_chunks = 0;
var upload_success = false;
var times = 0;
var interval = 0; //注册组件
WebUploader.Uploader.register({
'before-send': 'preupload'
}, {
preupload: function( block ) {
var me = this,
owner = this.owner,
deferred = WebUploader.Deferred();
chunks = block.chunks;
owner.md5File(block.blob)
//及时显示进度
.progress(function(percentage) {
console.log('Percentage:', percentage);
})
//如果读取出错了,则通过reject告诉webuploader文件上传出错。
.fail(function() {
deferred.reject();
console.log("==1==");
})
//md5值计算完成
.then(function( md5 ) {
if(arr_md5.contains(md5)){//数组中包含+(block.chunk+1)
deferred.reject();
console.log("分片已上传"+block.file.id);
$("#speed_"+block.file.id).text("正在断点续传中...");
if(block.end == block.total){
$("#speed_"+block.file.id).text("上传完毕");
$("#pro_"+block.file.id).css( 'width', '100%' );
}else{
$("#pro_"+block.file.id).css( 'width',(block.end/block.total) * 100 + '%' );
}
}else{
deferred.resolve();
console.log("开始上传分片:"+md5);
}
});
return deferred.promise();
}
}); //初始化WebUploader
var uploader = WebUploader.create({
//swf文件路径
//swf: 'http://www.ssss.com.cn/js/webuploader/Uploader.swf',
//文件接收服务端。
server: '/upload/UploadPhotoSlt?methodName=fileupload&tokenid='+$("#tokenid").val(),
//选择文件的按钮,可选。内部根据当前运行是创建,可能是input元素,也可能是flash.
pick: '#uploadBtn',
//不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
resize: false,
auto:true,
//是否分片
chunked :true,
//分片大小
chunkSize :1024*1024*2,
chunkRetry :3,
threads :3,//最大并发
fileNumLimit :1,
fileSizeLimit :1024*1024*1024*1024,
fileSingleSizeLimit: 1024*1024*1024,
duplicate :true,
accept: {
title: 'file',
extensions: 'jpg,png,ai,zip,rar,psd,pdf,cdr,psd,tif',
mimeTypes: '*/*'
}
}); //当文件被加入队列之前触发,此事件的handler返回值为false,则此文件不会被添加进入队列。
uploader.on('beforeFileQueued',function(file){
if(",jpg,png,ai,zip,rar,psd,pdf,cdr,psd,tif,".indexOf(","+file.ext+",")<0){
alert("不支持的文件格式");
}
}); //当有文件添加进来的时候
uploader.on( 'fileQueued', function( file ) {
times = 1;
var src = "http://www.wodexiangce.cn/images/type/JPG.jpg";
if(file.ext == 'jpg'){
src = "http://www.wodexiangce.cn/images/type/JPG.jpg";
}else if(file.ext == 'png'){
src = "http://www.wodexiangce.cn/images/type/PNG.jpg";
}else if(file.ext == 'ai'){
src = "http://www.wodexiangce.cn/images/type/AI.jpg";
}else if(file.ext == 'zip'){
src = "http://www.wodexiangce.cn/images/type/ZIP.jpg";
}else if(file.ext == 'rar'){
src = "http://www.wodexiangce.cn/images/type/RAR.jpg";
}else if(file.ext == 'psd'){
src = "http://www.wodexiangce.cn/images/type/PSD.jpg";
}else if(file.ext == 'pdf'){
src = "http://www.wodexiangce.cn/images/type/PDF.jpg";
}else if(file.ext == 'cdr'){
src = "http://www.wodexiangce.cn/images/type/CDR.jpg";
}else if(file.ext == 'tif'){
src = "http://www.wodexiangce.cn/images/type/TIF.jpg";
}
upload_success = false;
$("#list").html(
'<div class="clearfix"><img src='+src+' width="50px" class="icon-file" ></img>'+
'<div class="fl" style="margin-left: 70px;">'+
'<p class="speed font-12" id="speed_'+file.id+'">校验文件...</p>'+
'<div class="progress">'+
'<span id="pro_'+file.id+'" class="progressing"></span>'+
'</div>'+
'<span class="file-size">'+(file.size/1024/1024).toFixed(2)+'MB</span>'+
'<a href="javascript:void(0);" id="stopOretry_'+file.id+'" onclick="stop(\''+file.id+'\');" class="a-pause">暂停</a>'+
'</div></div><span class="file-name">'+file.name+'</span><br/>' );
//文件开始上传后开始计时,计算实时上传速度
interval = setInterval(function(){times++;},1000); }); //上传过程中触发,携带上传进度。文件上传过程中创建进度条实时显示。
uploader.on( 'uploadProgress', function( file, percentage ) {
var status_pre = file.size*percentage-arr_md5.length*2*1024*1024;
if(status_pre<=0){
return;
}
$("#pro_"+file.id).css( 'width', percentage * 100 + '%' );
var speed = ((status_pre/1024)/times).toFixed(0);
$("#speed_"+file.id).text(speed +"KB/S");
if(percentage == 1){
$("#speed_"+file.id).text("上传完毕");
}
}); //文件上传成功时触发
uploader.on( 'uploadSuccess', function( file,response) {
console.log("成功上传"+file.name+" res="+response);
$.ajax({
type:'get',
url:'/upload/UploadPhotoSlt',
dataType: 'json',
data: {
methodName:'composeFile',
name:file.name,
chunks:chunks,
tokenid:$("#tokenid").val()
},
async:false,
success: function(data) {
console.log("==compose=="+data.status);
if(data.status == "success"){
upload_success = true;
$("#url").val(data.url);
console.log(data.url);
}else{
upload_success = false;
alert(data.errstr);
}
}
});
}); //文件上传异常失败触发
uploader.on( 'uploadError', function( file,reason ) {
console.log("失败"+reason );
}); //某个文件开始上传前触发,一个文件只会触发一次。
uploader.on( 'uploadStart', function(file) {
console.info("file="+file.name);
//分片文件上传之前
$.ajax({
type:'get',
url:'/upload/UploadPhotoSlt',
dataType: 'json',
data: {
methodName:'md5Validation',
name:file.name,
tokenid:$("#tokenid").val()
},
async:false,
success: function(data) {
if(data.md5_arr != ""){
arr_md5 = data.md5_arr.split(",")
}else{
arr_md5 = new Array();
}
}
});
}); //当所有文件上传结束时触发。
uploader.on( 'uploadFinished', function() { }); function stop(id){
uploader.stop(true);
$("#stopOretry_"+id).attr("onclick","retry('"+id+"')");
$("#stopOretry_"+id).text("恢复");
clearInterval(interval);
}
function retry(id){
uploader.retry();
$("#stopOretry_"+id).attr("onclick","stop('"+id+"')");
$("#stopOretry_"+id).text("暂停");
interval = setInterval(function(){times++;},1000);
}

后端代码

后台Java代码,使用到commons-fileupload-1.1.1.jar

可以参考:Apache Commons FileUpload 实现文件上传

servlet:HttpServletBasic 

 package com.wodexiangce.web.servlet;

 import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils; public class HttpServletBasic extends HttpServlet{
private static final long serialVersionUID = 1L; protected WebApplicationContext wac = null; public void init() throws ServletException {
super.init();
ServletContext sc = this.getServletContext();
wac = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
} /**
* 方法转发器,通过方法名调用相应的方法 。
* 可以看出,不能分出方法同名而参数不同的方法 。
*/
protected void service(HttpServletRequest request,HttpServletResponse response){ String methodName = request.getParameter("methodName") ; //当前类所有的方法名称
Method[] methods = this.getClass().getDeclaredMethods() ;
for(Method m:methods){
if(m.getName().equals(methodName)){
try {
m.invoke(this, new Object[]{request,response}) ;
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
break ;
}
}
} public void destroy() {
wac = null;
} }

servlet:UploadPhotoSlt

 package com.wodexiangce.web.servlet;

 import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import net.sf.json.JSONObject; import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang.math.NumberUtils; import com.wodexiangce.persistence.model.WdxcQywFiles;
import com.wodexiangce.services.QywFileService;
import com.wodexiangce.util.FileUtils; public class UploadPhotoSlt extends HttpServletBasic{ private static final long serialVersionUID = 1L; /**
* 文件上传
* @param request
* @param response
* @throws IOException
*/
@SuppressWarnings({ "unchecked", "deprecation" })
public void fileupload(HttpServletRequest request, HttpServletResponse response)throws IOException{
try {
System.out.println("=================fileupload===================");
response.addHeader("Access-Control-Allow-Origin", "*");
String useridStr = request.getParameter("tokenid");
if(useridStr==null||"".equals(useridStr)||useridStr.length()<3){
response.getWriter().write(JSONObject.fromObject("{\"status\":\"error\",'errstr':'token校验错误'}").toString());
return;
}
long userid = Long.parseLong(useridStr);
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory); // 得到所有的表单域,它们目前都被当作FileItem
List<FileItem> fileItems = upload.parseRequest(request); String id = "";
String fileName = "";
// 如果大于1说明是分片处理
int chunks = 1;
int chunk = 0;
FileItem tempFileItem = null;
for (FileItem fileItem : fileItems) {
if (fileItem.getFieldName().equals("id")) {
id = fileItem.getString();
} else if (fileItem.getFieldName().equals("name")) {
fileName = new String(fileItem.getString().getBytes("ISO-8859-1"), "UTF-8");
} else if (fileItem.getFieldName().equals("chunks")) {
chunks = NumberUtils.toInt(fileItem.getString());
} else if (fileItem.getFieldName().equals("chunk")) {
chunk = NumberUtils.toInt(fileItem.getString());
} else if (fileItem.getFieldName().equals("file")) {
tempFileItem = fileItem;
}
}
System.out.println("id="+id+" filename="+fileName+" chunks="+chunks+" chunk="+chunk+" size="+tempFileItem.getSize());
//临时目录用来存放所有分片文件
String tempFileDir = getTempFilePath()+ File.separator + userid;
File parentFileDir = new File(tempFileDir);
if (!parentFileDir.exists()) {
parentFileDir.mkdirs();
}
//分片处理时,前台会多次调用上传接口,每次都会上传文件的一部分到后台
File tempPartFile = new File(parentFileDir, fileName + "_" + chunk+ ".part"); String MD5 = FileUtils.copyInputStreamToFile(tempFileItem.getInputStream(),tempPartFile);
int count = 0;
while(MD5==null&&count<3){
MD5 = FileUtils.copyInputStreamToFile(tempFileItem.getInputStream(),tempPartFile);
count++;
}
if(MD5==null){
throw new Exception("分片文件:"+chunk+"上传失败");
}
//分片文件上传成功以后,重命名分片文件,规则:原名之前拼接MD5码
tempPartFile.renameTo(new File(parentFileDir, fileName + "_" + chunk+"_"+MD5+ ".part"));
System.out.println("MD5="+MD5);
response.getWriter().write(JSONObject.fromObject("{\"md5\":\""+MD5+"\"}").toString());
}
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 重复验证
* @param request
* @param response
* @throws IOException
*/
public void md5Validation(HttpServletRequest request, HttpServletResponse response)throws IOException{
try {
System.out.println("=================md5Validation===================");
response.addHeader("Access-Control-Allow-Origin", "*");
response.setCharacterEncoding("utf-8");
String useridStr = request.getParameter("tokenid");
if(useridStr==null||"".equals(useridStr)||useridStr.length()<3){
response.getWriter().write(JSONObject.fromObject("{\"status\":\"error\",'errstr':'token校验错误'}").toString());
return;
}
long userid = Long.parseLong(useridStr);
String tempFileDir = getTempFilePath()+ File.separator + userid;
File parentFileDir = new File(tempFileDir);
if (!parentFileDir.exists()) {
response.getWriter().write(JSONObject.fromObject("{\"md5_arr\":\"\"}").toString());
return;
}
String fileName = request.getParameter("name");
fileName = new String(fileName.getBytes("ISO-8859-1"),"UTF-8");
System.out.println("fileName="+fileName); StringBuffer sb = new StringBuffer();
for(File file:parentFileDir.listFiles()){
String name = file.getName();
if(name.endsWith(".part") && name.startsWith(fileName)){
//此文件有上传记录,解析MD5
name = name.substring(name.lastIndexOf("_")+1,name.lastIndexOf(".part"));
if(name.length()==32){
if(sb.length()>0){
sb.append(",");
}
sb.append(name);
}
}
}
response.getWriter().write(JSONObject.fromObject("{\"md5_arr\":\""+sb.toString()+"\"}").toString());
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 文件所有分片上传完毕之后,保存文件数据到数据库
* @param request
* @param response
* @throws IOException
*/
public void composeFile(HttpServletRequest request, HttpServletResponse response)throws IOException{
try {
System.out.println("=================composeFile===================");
response.addHeader("Access-Control-Allow-Origin", "*");
response.setCharacterEncoding("utf-8");
String useridStr = request.getParameter("tokenid");
if(useridStr==null||"".equals(useridStr)||useridStr.length()<3){
response.getWriter().write(JSONObject.fromObject("{\"status\":\"error\",'errstr':'token校验错误'}").toString());
return;
}
long userid = Long.parseLong(useridStr);
String tempFileDir = getTempFilePath()+ File.separator + userid;
File parentFileDir = new File(tempFileDir);
if (!parentFileDir.exists()) {
response.getWriter().write(JSONObject.fromObject("{\"status\":\"error\",'errstr':'目录不存在'}").toString());
return;
}
String fileName = request.getParameter("name");
fileName = new String(fileName.getBytes("ISO-8859-1"),"UTF-8");
String chunks = request.getParameter("chunks");
System.out.println("fileName="+fileName);
Map<String,File> chunkFileMap = new HashMap<String, File>(); String md5 = null;
for(File file:parentFileDir.listFiles()){
String name = file.getName();
if(name.endsWith(".part") && name.startsWith(fileName)){
md5 = name.substring(name.lastIndexOf("_")+1,name.lastIndexOf(".part"));
System.out.println("md5="+md5);
if(md5.length()==32){//完整的分片文件
String index = name.replace(fileName, "").replace("_"+md5+".part", "").replace("_", "");
chunkFileMap.put(index, file);
}
}
}
//分片总数和分片文件数一致,则证明分片文件已完整上传,可以持久化数据
if(chunkFileMap.size() == Integer.parseInt(chunks.trim())){
System.out.println("===========开始合并文件分片==========");
WdxcQywFiles QywFile = new WdxcQywFiles();
QywFile.setFilename(fileName);
QywFile.setCreatetime(new Date());
QywFile.setFilepath("/site/photos/file/"+userid+"/"+fileName);
QywFile.setFiledownurl("http://www.sssss.cn/file/"+userid+"/"+fileName); //AI、PDF、EPS、CDR、PSD、JPG、TIFF
if(fileName.toLowerCase().endsWith(".tif")){
QywFile.setFilepreview("http://www.wodexiangce.cn/images/type/TIF.jpg");
}else if(fileName.toLowerCase().endsWith(".jpg")){
QywFile.setFilepreview("http://www.wodexiangce.cn/images/type/JPG.jpg");
}else if(fileName.toLowerCase().endsWith(".psd")){
QywFile.setFilepreview("http://www.wodexiangce.cn/images/type/PSD.jpg");
}else if(fileName.toLowerCase().endsWith(".ai")){
QywFile.setFilepreview("http://www.wodexiangce.cn/images/type/AI.jpg");
}else if(fileName.toLowerCase().endsWith(".cdr")){
QywFile.setFilepreview("http://www.wodexiangce.cn/images/type/CDR.jpg");
}else if(fileName.toLowerCase().endsWith(".zip")){
QywFile.setFilepreview("http://www.wodexiangce.cn/images/type/ZIP.jpg");
}else if(fileName.toLowerCase().endsWith(".pdf")){
QywFile.setFilepreview("http://www.wodexiangce.cn/images/type/PDF.jpg");
}else if(fileName.toLowerCase().endsWith(".png")){
QywFile.setFilepreview("http://www.wodexiangce.cn/images/type/PNG.jpg");
}else if(fileName.toLowerCase().endsWith(".rar")){
QywFile.setFilepreview("http://www.wodexiangce.cn/images/type/RAR.jpg");
}
QywFile.setUserid(userid);
FileUtils.fileCompose(QywFile, chunkFileMap);//合并文件
File file = new File(QywFile.getFilepath());
if(!file.exists()){
System.out.println("文件合并失败:"+QywFile.getFilepath());
response.getWriter().write(JSONObject.fromObject("{\"status\":\"error\",'errstr':'文件合并失败'}").toString());
return;
} //把文件路径保存到数据库
QywFileService fileService = (QywFileService)wac.getBean("qywFileService");
Long fileid = (Long)fileService.saveQywFile(QywFile);
System.out.println("文件保存成功:"+fileid); response.getWriter().write(JSONObject.fromObject("{\"status\":\"success\",'url':'"+QywFile.getFiledownurl()+"'}").toString());
}else{
System.out.println("分片数量不正确,实际分片数量:"+chunkFileMap.size()+" 总分片数量:"+chunks);
response.getWriter().write(JSONObject.fromObject("{\"status\":\"error\",'errstr':'分片数量不正确'}").toString());
}
} catch (Exception e) {
e.printStackTrace();
System.err.println("文件合并失败:"+e.getMessage());
response.getWriter().write(JSONObject.fromObject("{\"status\":\"error\",'errstr':'文件合并失败'}").toString());
}
} /**
* 指定临时目录
* @return
*/
private String getTempFilePath(){
return "/site/xxxxxx/temp";
} }

补充:涉及到的实体类和工具类

 package com.wodexiangce.persistence.model;

 import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date; public class WdxcQywFiles implements Serializable{ private static final long serialVersionUID = 1L; private long id; private long userid; private String filename; private String filepreview; private String filepath; private int deleted; private Date deletedtime; private Date createtime; private String filedownurl; private BigDecimal filesize; public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public long getUserid() {
return userid;
}
public void setUserid(long userid) {
this.userid = userid;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public String getFilepreview() {
return filepreview;
}
public void setFilepreview(String filepreview) {
this.filepreview = filepreview;
}
public String getFilepath() {
return filepath;
}
public void setFilepath(String filepath) {
this.filepath = filepath;
}
/**
* 删除状态 0:正常 1:已删除
* @return
*/
public int getDeleted() {
return deleted;
}
public void setDeleted(int deleted) {
this.deleted = deleted;
}
public Date getDeletedtime() {
return deletedtime;
}
public void setDeletedtime(Date deletedtime) {
this.deletedtime = deletedtime;
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
/**
* 文件下载URL前缀(需拼写分片名称)
* @return
*/
public String getFiledownurl() {
return filedownurl;
}
public void setFiledownurl(String filedownurl) {
this.filedownurl = filedownurl;
}
/**
* 文件大小
* @return
*/
public BigDecimal getFilesize() {
return filesize;
}
public void setFilesize(BigDecimal bigDecimal) {
this.filesize = bigDecimal;
}
}
 package com.wodexiangce.util;

 import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.AccessController;
import java.security.MessageDigest;
import java.security.PrivilegedAction;
import java.util.Map; import com.wodexiangce.persistence.model.WdxcQywFiles; /**
* 文件处理工具类
*/
public class FileUtils {
/**
* 保存文件流到文件,同时返回文件MD5
* @param inputStream
* @param file
*/
public static String copyInputStreamToFile(InputStream inputStream,File file){
MessageDigest md = null;
try {
if(inputStream == null || inputStream == null) {
return null;
}
md = MessageDigest.getInstance("MD5");
byte[] b = new byte[102400];//set b 100Kb byte.
int n = inputStream.read(b);
int totalBytes = n;
FileOutputStream fos = new FileOutputStream(file);
while (n > -1) {
fos.write(b, 0, n);
fos.flush();
n = inputStream.read(b);
totalBytes += n;
}
fos.close();
inputStream.close();
System.out.println("文件总大小:"+totalBytes);
//生成文件MD5值
FileInputStream in = new FileInputStream(file);
//文件内存映射,提高读写超大文件可能和速度,但会造成文件锁定不可操作。
MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
md.update(byteBuffer);
clean(byteBuffer); byte[] encrypt = md.digest();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < encrypt.length; i++) {
String hex = Integer.toHexString(0xff & encrypt[i]);
if (hex.length() == 1)
sb.append('0');
sb.append(hex);
}
in.close();
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
} /**
* 文件合并
* @param QywFile
* @param chunkFileMap
*/
public static void fileCompose(WdxcQywFiles QywFile,Map<String,File> chunkFileMap){
String path = QywFile.getFilepath();
File mainFile = new File(path);
if(!mainFile.getParentFile().exists()){
mainFile.getParentFile().mkdirs();
}
try {
FileChannel out = new FileOutputStream(mainFile).getChannel();
FileChannel in = null;
long start = System.currentTimeMillis();
for(int i=0;i<chunkFileMap.size();i++){
File file = chunkFileMap.get(String.valueOf(i));
System.out.println("file="+file.getName());
in = new FileInputStream(file).getChannel();
MappedByteBuffer buf = in.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
out.write(buf);
in.close();
FileUtils.clean(buf);
}
System.out.println("文件大小:"+mainFile.length()/1024/1024+" M");
QywFile.setFilesize(new BigDecimal(mainFile.length()));
long end = System.currentTimeMillis();
System.out.println("常规方法合并耗时:"+(end-start)/1000+" 秒");
}catch (Exception e) {
e.printStackTrace();
}
} @SuppressWarnings("unchecked")
public static void clean(final Object buffer) throws Exception {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
try {
Method getCleanerMethod = buffer.getClass().getMethod("cleaner",new Class[0]);
getCleanerMethod.setAccessible(true);
sun.misc.Cleaner cleaner =(sun.misc.Cleaner)getCleanerMethod.invoke(buffer,new Object[0]);
cleaner.clean();
} catch(Exception e) {
e.printStackTrace();
}
return null;}
});
}
}
上一篇:Atitit..文件上传组件选型and最佳实践总结(3)----断点续传控件的实现


下一篇:jQuery.uploadify文件上传组件实例讲解