文件上传前检测客户端文件大小的三种方法
前段时间,因工作需要,需要在文件上传时限制文件的大小,所以需要在上传之前检测文件的大小。
方法一:js检测文件大小
一开始的想法是通过js直接在前端检测文件大小,代码如下:
//获取上传文件大小 function getFileSize(filePath) { var vBrowserVersion = getBrowserVersion(); if("MSIE6.0" == vBrowserVersion){//对于IE6,使用Image的fileSize属性进行判断文件大小 var image=new Image(); image.dynsrc=filePath; return image.fileSize; }else if(vBrowserVersion.indexOf("MSIE")>=0){//对于IE6以上浏览器(IE6是公司默认最低版本),使用ActiveXObject进行上传 var fso = new ActiveXObject("Scripting.FileSystemObject"); return fso.GetFile(filePath).size; }else{//其它的浏览器,也是采用Image的fileSize属性进行判断文件大小 var image=new Image(); image.dynsrc = filePath; return image.fileSize; } }
但这种方法存在一些弊端:
1、IE6下面是利用的Image标签的dynsrc属性去判断;
2、IE8下面使用ActiveXObject进行上传的话,是IE安全机制不支持的,需要降低本地浏览器的安全设置,对于开发者来说,是不可能去限制用户的。
故这种方法不可行。
方法二:java读取文件流方式
接着的一种做法是通过dwr的方式,将文件路径传到后台去,再去读取文件的大小。代码如下:
1 /** 2 * 读取单据所带的附件总大小 3 * 4 * @param filaPath 准备上传的文件的路径 5 * @param moduleKey 文件对象类型 6 * @param moduleObjectId 文件对象ID 7 * @return lAttachmentTotalSize 该单据的附件总大小 8 * @throws AttachmentException 9 */ 10 public static long getAttachmentTotalSize(String filePath, String moduleKey, String moduleObjectId) 11 throws AttachmentException { 12 // 附件总大小 13 long lAttachmentTotalSize = 0; 14 // 准备上传的文件大小 15 long lAttachmentSize = 0; 16 // 已经保存的附件的大小 17 long lExistAttachmentSize = 0; 18 FileInputStream fis = null; 19 // 根据对象类型和对象ID查询出已经保存的附件 20 List lstAttachment = queryAttachmentList(moduleKey, moduleObjectId); 21 if (null != lstAttachment && lstAttachment.size() > 0) { 22 for (int i = 0, iSize = lstAttachment.size(); i < iSize; i++) { 23 AttachmentVO vo = (AttachmentVO) lstAttachment.get(i); 24 // 读取附件的大小,并累加 25 lExistAttachmentSize += vo.getFileSize(); 26 } 27 } 28 // 根据filePath读取准备上传的文件大小,与已经保存的文件大小相加 29 try { 30 File ff = new File(filePath); 31 if (ff.exists()) { 32 fis = new FileInputStream(ff); 33 lAttachmentSize = fis.available(); 34 } else { 35 logger.error("AttachmentUtil.getAttachmentTotalSize方法,获取准备上传的文件时,文件不存在"); 36 } 37 } catch (IOException ex) { 38 logger.error("AttachmentUtil.getAttachmentTotalSize方法,读取文件大小时发生异常", ex); 39 } finally { 40 // 关闭流 41 try { 42 if (null != fis) { 43 fis.close(); 44 } 45 } catch (IOException ex) { 46 logger.error("关闭流时发生异常", ex); 47 } 48 } 49 // 附件总大小=已经存在的附件大小+准备上传的附件大小 50 lAttachmentTotalSize = lExistAttachmentSize + lAttachmentSize; 51 return lAttachmentTotalSize; 52 }
这个方法也存在一些弊端:
1、服务器端在读取文件路径时,是访问不了客户端的文件的,它只会放在服务器端自己对应路径下的文件,但往往这个路径下是不存在对应文件的,故读取出来的文件大小总为0;
2、IE8下由于安全问题,服务端获取客户端文件的路径,会变为C:/fakePath问题,这个问题在下一篇文章中会有解决方案;
方法三:Ajax异步提交表单获取文件大小
最后采取的一种方法是,通过Ajax进行异步的表单提交,因为form里面使用了file标签,是可以拿到文件的大小的。代码如下:
1 //定义ajax异步提交form时需要的参数 2 var options = { 3 url:'<common:webRoot/>/product/attachment/attachmentMultiAction.do?queryType=getAttachmentTotalSize', 4 success:successReturn, 5 type:'post' 6 }; 7 //ajax异步提交form 8 jQuery("#attachmentForm").ajaxSubmit(options); 9 10 11 12 //ajax返回后回调方法 13 function successReturn(data){ 14 //后台返回的消息固定为FileTooLarge 15 if("FileTooLarge" == data){ 16 var vMessage = "您添加的附件文件总大小超过(<%=AttachmentInfo.ATTACHMENT_SIZE/1024/1024%>M),请压缩文件或者重新选择。"; 17 alert(vMessage); 18 }else{//返回消息为空时,则正常提交form,上传文件 19 document.attachmentForm.target = "_self"; 20 document.attachmentForm.action = "<common:webRoot/>/product/attachment/attachmentMultiAction.do"; 21 document.attachmentForm.submit(); 22 window.loadingImg.style.visibility = "visible"; 23 } 24 }
其中successReturn是返回后调用的方法,如果文件过大则进行提示,否则重新提交,进行上传。
关于Ajax异步提交表单的详细介绍,会在下一篇文章中介绍。
这种方法的好处是不受客户端和服务器端的安全性影响,不好的地方是会先进行一个异步提交,需要消耗一定资源,当然因为是异步的,只要不是上传特别大的附件而导致检测过程过长,页面端的响应效果还是没什么太大的影响。