• 断点上传能够防止意外情况导致上传一半的文件下次上传时还要从头下载,网上有很多关于断点的实现,这篇文章只是从前到后完整的记录下一个可用的实例,由于生产环境要求不高,而且就是提供给一两个人用,所以我简化了诸多过程,不用flash,也不用applet,只是通过html5的新特性进行浏览器端的处理。
  • 简单说下关键点
  1. 如果上次传到n字节,那么浏览器下次续传直接就是从文件的n字节开始向服务器传送数据,而不是都传过去,服务器从n字节开始接收。
  2. html5能给文件分片,所以每次上传完一块文件后,应该返回当前已经上传的文件大小,好让h5能从此断点继续读取。
  3. 前端的js是网上别人的底子,我进行了可用性修改。
  4. 代码完全可用,而且都是用的最简单的东西实现
  5. 可以看到我用了本地文件的最后修改时间这个属性,因为这样可以脱离数据库只通过文件名+文件最后修改时间来确定文件的唯一性,如果生产中有数据库的接入,建议先生成续传文件并返回对应的唯一id。
  • 服务器端方法
  1. 获取当前已经上传文件的大小
     /**
* 获取已上传的文件大小
* @param request
* @param response
*/
public void getChunkedFileSize(HttpServletRequest request,HttpServletResponse response){
//存储文件的路径,根据自己实际确定
String currentFilePath = "c:\\uploadFile\\Image\\";
PrintWriter print = null;
try {
request.setCharacterEncoding("utf-8");
print = response.getWriter();
String fileName = new String(request.getParameter("fileName").getBytes("ISO-8859-1"),"UTF-8");
String lastModifyTime = request.getParameter("lastModifyTime");
File file = new File(currentFilePath+fileName+"."+lastModifyTime);
if(file.exists()){
print.print(file.length());
}else{
print.print(-1);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }

2.文件上传

/**
*
* 断点文件上传 1.先判断断点文件是否存在 2.存在直接流上传 3.不存在直接新创建一个文件 4.上传完成以后设置文件名称
*
*/
public static void appendUpload2Server(HttpServletRequest request,HttpServletResponse response) {
PrintWriter print = null;
try {
request.setCharacterEncoding("utf-8");
print = response.getWriter();
String fileSize = request.getParameter("fileSize");
long totalSize = StringUtil.toLong(fileSize);
RandomAccessFile randomAccessfile = null;
long currentFileLength = 0;// 记录当前文件大小,用于判断文件是否上传完成
String currentFilePath = "c:\\uploadFile\\Image\\";// 记录当前文件的绝对路径
String fileName = new String(request.getParameter("fileName").getBytes("ISO-8859-1"),"UTF-8");
String lastModifyTime = request.getParameter("lastModifyTime");
File file = new File(currentFilePath+fileName+"."+lastModifyTime);
// 存在文件
if(file.exists()){
randomAccessfile = new RandomAccessFile(file, "rw");
}
else {
// 不存在文件,根据文件标识创建文件
randomAccessfile = new RandomAccessFile(currentFilePath+fileName+"."+lastModifyTime, "rw");
}
// 开始文件传输
InputStream in = request.getInputStream();
randomAccessfile.seek(randomAccessfile.length());
byte b[] = new byte[1024];
int n;
while ((n = in.read(b)) != -1) {
randomAccessfile.write(b, 0, n);
} currentFileLength = randomAccessfile.length(); // 关闭文件
closeRandomAccessFile(randomAccessfile);
randomAccessfile = null;
// 整个文件上传完成,修改文件后缀
if (currentFileLength == totalSize) {
File oldFile = new File(currentFilePath+fileName+"."+lastModifyTime);
File newFile = new File(currentFilePath+fileName);
if(!oldFile.exists()){
return;//重命名文件不存在
}
if(newFile.exists()){// 如果存在形如test.txt的文件,则新的文件存储为test+当前时间戳.txt, 没处理不带扩展名的文件
String newName = fileName.substring(0,fileName.lastIndexOf("."))
+System.currentTimeMillis()+"."
+fileName.substring(fileName.lastIndexOf(".")+1);
newFile = new File(currentFilePath+newName);
}
if(!oldFile.renameTo(newFile)){
oldFile.delete();
} }
print.print(currentFileLength); } catch (Exception e) {
e.printStackTrace();
}
}
/**
* 关闭随机访问文件
*
* @param randomAccessfile
*/
public static void closeRandomAccessFile(RandomAccessFile rfile) {
if (null != rfile) {
try {
rfile.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
  • jsp页面
<html>
<head>
<title>断点续传文件</title>
<meta charset="utf-8">
</head> <body onload="init();">
<div class="row">
<label for="fileToUpload">请选择需要上传的文件</label>
<input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected();" multiple/>
</div> </div>
<div class="row">
<button onclick="uploadFiles()">上传</button>
<button onclick="pauseUpload()">暂停</button>
&nbsp;<label id="progressNumber"></label>
</div>
<div id="msg" style="max-height: 400px; overflow:auto;min-height: 100px;">
</div>
<br>
<div><h6>支持批量,支持断点续传</h6></div>
</body>
</html>
  • js代码
var msg = null;
var paragraph = 1024*1024*2; //每次分片传输文件的大小 2M
var blob = null;// 分片数据的载体Blob对象
var fileList = null; //传输的文件
var uploadState = 0; // 0: 无上传/取消, 1: 上传中, 2: 暂停 //初始化消息框
function init(){
msg = document.getElementById("msg");
}
function uploadFiles(){
//将上传状态设置成1
uploadState = 1;
if(fileList.files.length>0){
for(var i = 0; i< fileList.files.length; i++){
var file = fileList.files[i];
uploadFileInit(file,i);
}
}else{
msg.innerHTML = "请选择上传文件!";
}
}
/**
* 获取服务器文件大小,开始续传
* @param file
* @param i
*/
function uploadFileInit(file,i){
if(file){
var startSize = 0;
var endSize = 0;
var date = file.lastModifiedDate;
var lastModifyTime = date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate()+"-"
+date.getHours()+"-"+date.getMinutes()+"-"+date.getSeconds()
//获取当前文件已经上传大小
jQuery.post("xxx/getChunkedFileSize.do",
{"fileName":encodeURIComponent(file.name),"fileSize":file.size,"lastModifyTime":lastModifyTime,"chunkedFileSize":"chunkedFileSize"},
function(data){
if(data != -1){
endSize = Number(data);
}
uploadFile(file,startSize,endSize,i); }); }
}
/**
* 分片上传文件
*/
function uploadFile(file,startSize,endSize,i) {
var date = file.lastModifiedDate;
var lastModifyTime = date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate()+"-"
+date.getHours()+"-"+date.getMinutes()+"-"+date.getSeconds()
var reader = new FileReader();
reader.onload = function loaded(evt) {
// 构造 XMLHttpRequest 对象,发送文件 Binary 数据
var xhr = new XMLHttpRequest();
xhr.sendAsBinary = function(text){
var data = new ArrayBuffer(text.length);
var ui8a = new Uint8Array(data, 0);
for (var i = 0; i < text.length; i++) ui8a[i] = (text.charCodeAt(i) & 0xff);
this.send(ui8a);
} xhr.onreadystatechange = function(){
if(xhr.readyState==4){
//表示服务器的相应代码是200;正确返回了数据
if(xhr.status==200){
//纯文本数据的接受方法
var message=xhr.responseText;
message = Number(message);
uploadProgress(file,startSize,message,i);
} else{
msg.innerHTML = "上传出错,服务器相应错误!";
}
}
};//创建回调方法
xhr.open("POST",
"xxx/appendUpload2Server.do?fileName=" + encodeURIComponent(file.name)+"&fileSize="+file.size+"&lastModifyTime="+lastModifyTime,
false);
xhr.overrideMimeType("application/octet-stream;charset=utf-8");
xhr.sendAsBinary(evt.target.result);
};
if(endSize < file.size){
//处理文件发送(字节)
startSize = endSize;
if(paragraph > (file.size - endSize)){
endSize = file.size;
}else{
endSize += paragraph ;
}
if (file.webkitSlice) {
//webkit浏览器
blob = file.webkitSlice(startSize, endSize);
}else
blob = file.slice(startSize, endSize);
reader.readAsBinaryString(blob);
}else{
document.getElementById('progressNumber'+i).innerHTML = '100%';
}
} //显示处理进程
function uploadProgress(file,startSize,uploadLen,i) {
var percentComplete = Math.round(uploadLen * 100 / file.size);
document.getElementById('progressNumber'+i).innerHTML = percentComplete.toString() + '%';
//续传
if(uploadState == 1){
uploadFile(file,startSize,uploadLen,i);
}
} /*
暂停上传
*/
function pauseUpload(){
uploadState = 2;
} /**
* 选择文件之后触发事件
*/
function fileSelected() {
fileList = document.getElementById('fileToUpload');
var length = fileList.files.length;
var frame = document.getElementById('fileFrame');
for(var i=0; i<length; i++){
file = fileList.files[i];
if(file){
var fileSize = 0;
if (file.size > 1024 * 1024)
fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
else
fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';
var nameDiv = document.createElement("div");
nameDiv.setAttribute("id","fileName"+i);
nameDiv.innerHTML='Name: ' + file.name;
var sizeDiv = document.createElement("div");
sizeDiv.setAttribute("id","fileSize"+i);
sizeDiv.innerHTML='fileSize: ' + fileSize;
var typeDiv = document.createElement("div");
typeDiv.setAttribute("id","progressNumber"+i);
typeDiv.innerHTML='';
}
frame.appendChild(nameDiv);
frame.appendChild(sizeDiv);
frame.appendChild(typeDiv);
}
}

文件断点上传,html5实现前端,java实现服务器的更多相关文章

  1. 后端springmvc,前端html5的FormData实现文件断点上传

    前言 最近项目中有使用到文件断点上传,得空便总结总结,顺便记录一下,毕竟“好记性不如烂笔头”. 后端代码: package com.test.controller; import java.io.Bu ...

  2. java HTTP文件断点上传

    之前仿造uploadify写了一个HTML5版的文件上传插件,没看过的朋友可以点此先看一下~得到了不少朋友的好评,我自己也用在了项目中,不论是用户头像上传,还是各种媒体文件的上传,以及各种个性的业务需 ...

  3. java文件断点上传

    1,项目调研 因为需要研究下断点上传的问题.找了很久终于找到一个比较好的项目. 在GoogleCode上面,代码弄下来超级不方便,还是配置hosts才好,把代码重新上传到了github上面. http ...

  4. Android中Socket大文件断点上传

    原文:http://blog.csdn.net/shimiso/article/details/8529633 什么是Socket? 所谓Socket通常也称作“套接字”,用于描述IP地址和端口,是一 ...

  5. asp.net 如何实现大文件断点上传功能?

    之前仿造uploadify写了一个HTML5版的文件上传插件,没看过的朋友可以点此先看一下~得到了不少朋友的好评,我自己也用在了项目中,不论是用户头像上传,还是各种媒体文件的上传,以及各种个性的业务需 ...

  6. jsp文件断点上传

    之前仿造uploadify写了一个HTML5版的文件上传插件,没看过的朋友可以点此先看一下~得到了不少朋友的好评,我自己也用在了项目中,不论是用户头像上传,还是各种媒体文件的上传,以及各种个性的业务需 ...

  7. Android应用开发之使用Socket进行大文件断点上传续传

    http://www.linuxidc.com/Linux/2012-03/55567.htm http://blog.csdn.net/shimiso/article/details/8529633 ...

  8. php文件断点上传

    前段时间做视频上传业务,通过网页上传视频到服务器. 视频大小 小则几十M,大则 1G+,以一般的HTTP请求发送数据的方式的话,会遇到的问题:1,文件过大,超出服务端的请求大小限制:2,请求时间过长, ...

  9. jsp+servlet怎么实现文件断点上传下载

    我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用. 这次项目的需求: 支持大文件的上传和续传,要求续传支持所有浏览器,包括ie6,ie7,i ...

随机推荐

  1. JSP简单实现登录和注销

    JSP简单实现登录和注销 需求:用户登录成功后跳转到欢迎页面 用户登录失败跳转到初始的登录界面 用户点击注销,用户退出登录状态需要重新登录 登录页面的JSP代码: <%@ page langua ...

  2. Spring_Spring与AOP_AspectJ基于XML的实现

    一.前置通知 import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.as ...

  3. 设计模式 UML & java code

    A: 创造性模式 1. 工厂方法模式(FactoryMethod) 1.1 类图 1.2 代码1 public interface Pet { public String petSound(); } ...

  4. HTML contenteditable 属性

    contenteditable 属性是 HTML5 中的新属性,所有的主流浏览器都支持 contenteditable 属性. contenteditable 属性规定了元素内容是否可编辑. * 如果 ...

  5. Google APAC----Africa 2010, Qualification Round(Problem C. T9 Spelling)----Perl 解法

    原题地址链接:https://code.google.com/codejam/contest/351101/dashboard#s=p2 问题描述: Problem The Latin alphabe ...

  6. GDAL2.0编译——32位和64位

    准备工作: Source下载,这里下载对应的GDAL版本 https://trac.osgeo.org/gdal/wiki/DownloadSource 懒得编译也可以在这里下载对应版本 https: ...

  7. 自学git心得-4

    本节介绍分支的一些具体应用实例. 1.Bug分支 设想我们正在分支dev上工作,突然接到一个修复bug的命令,我们需要创建分支issue-101来修复它,在此之前我们肯定需要先保存我们当前未完成的工作 ...

  8. json 对象里面含有 =的解决办法

    今天通过restful 调用接口的时候,遇到这样的问题,通过接口返回的数据如下: { "code": 0, "message": "成功", ...

  9. SVN的正确提交方式

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/Rundy_Deng/article/details/80338093 也会让我们百思不得其解,甚至耽 ...

  10. C#中Equals和= =(等于号)的比较(转)

    一.           值类型的比较 对于值类型来说  两者比较的都是”内容”是否相同,即 值 是否一样,很显然此时两者是划等号的. 例: int i = 9; int j = 9; Console ...