文件断点上传,html5实现前端,java实现服务器

  • 断点上传能够防止意外情况导致上传一半的文件下次上传时还要从头下载,网上有很多关于断点的实现,这篇文章只是从前到后完整的记录下一个可用的实例,由于生产环境要求不高,而且就是提供给一两个人用,所以我简化了诸多过程,不用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);
        }
}
时间: 2024-11-09 18:18:59

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

Android 文件断点上传器[多用户并发访问]

通过TCP/IP(SOCKET)协议实现文件断点上传(实现多用户并发访问). HTTP不支持文件断点续传,所以无法使用HTTP协议. 场景: 1. 网络不稳定,导致上传失败,下次不是从头开始,而是从断点开始上传: 2. 上传大文件,无法http上传,因为web服务器考虑到安全因素,会限制文件大小,一般10+m. 此文件断点上传器使用自定义协议. 服务器为上传的文件在服务器端生成唯一的sourceid关联上传文件,当客户端上传文件时,首次的sourceid为空,服务端先判断sourceid是否为空

Android中Socket大文件断点上传

什么是Socket? 所谓Socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信连的句柄,应用程序通常通过“套接字”向网络发送请求或者应答网络请求,它就是网络通信过程中端点的抽象表示.它主要包括以下两个协议: TCP (Transmission Control Protocol 传输控制协议):传输控制协议,提供的是面向连接.可靠的字节流服务.当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据.TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功

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

http://www.linuxidc.com/Linux/2012-03/55567.htm http://blog.csdn.net/shimiso/article/details/8529633/ 在Android中上传文件可以采用HTTP方式,也可以采用Socket方式,但是HTTP方式不能上传大文件,这里介绍一种通过Socket方式来进行断点续传的方式,服务端会记录下文件的上传进度,当某一次上传过程意外终止后,下一次可以继续上传,这里用到的其实还是J2SE里的知识. 这个上传程序的原理

JSP如何实现文件断点上传和断点下载?

核心原理: 该项目核心就是文件分块上传.前后端要高度配合,需要双方约定好一些数据,才能完成大文件分块,我们在项目中要重点解决的以下问题. * 如何分片: * 如何合成一个文件: * 中断了从哪个分片开始. 如何分,利用强大的js库,来减轻我们的工作,市场上已经能有关于大文件分块的轮子,虽然程序员的天性曾迫使我重新造轮子.但是因为时间的关系还有工作的关系,我只能罢休了.最后我选择了百度的WebUploader来实现前端所需. 如何合,在合之前,我们还得先解决一个问题,我们如何区分分块所属那个文件的

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

我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用. 这次项目的需求: 支持大文件的上传和续传,要求续传支持所有浏览器,包括ie6,ie7,ie8,ie9,Chrome,Firefox,360安全浏览器,并且刷新浏览器后仍然能够续传,重启浏览器(关闭浏览器后再打开)仍然能够继续上传,重启电脑后仍然能够上传 支持文件夹的上传,要求服务端能够保留层级结构,并且能够续传.需要支持10万个以上的文件夹上传. 支持低版本的系统和浏览器,因为这个项目

php中文件断点上传怎么实现?

1.使用PHP的创始人 Rasmus Lerdorf 写的APC扩展模块来实现(http://pecl.php.net/package/apc) APC实现方法: 安装APC,参照官方文档安装,可以使用PECL模块安装方法快速简捷,这里不说明 配置php.ini,设置参数 apc.rfc1867=1 ,使APC支持上传进度条功能,在APC源码说明文档里面有说明 代码范例: 大文件(50G)上传的实现细节: 服务端接收文件数据的处理逻辑代码: 2.使用PECL扩展模块uploadprogress实

asp.net文件断点上传

HTML部分 <%@PageLanguage="C#"AutoEventWireup="true"CodeBehind="index.aspx.cs"Inherits="up6.index" %> <!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/

ASP.NET大文件断点上传

HTML部分 <%@PageLanguage="C#"AutoEventWireup="true"CodeBehind="index.aspx.cs"Inherits="up6.index" %> <!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/

实现TCP断点上传,后台C#服务实现接收

实现TCP断点上传,后台C#服务实现接收 终端实现大文件上传一直都是比较难的技术,其中涉及到后端与前端的交互,稳定性和流量大小,而且实现原理每个人都有自己的想法,后端主流用的比较多的是Http来实现,因为大多实现过断点下载.但稳定性不能保证,一旦断开,无法续传.所以得采用另一种流行的做法,TCP上传大文件. 网上查找了一些资料,大多数是断点下载,然后就是单独的C#端的上传接收,或是HTTP的,或是只有android端的,由于任务紧所以之前找的首选方案当然是Http先来实现文件上传,终端采用Pos