断点上传,java里面比较靠谱一点的,一般都会选用Flex。我承认,Flex只是摸了一下,不精通。HTML 5 有个Blob对象(File对象继承它),这个对象有个方法slice方法,可以对一个文件进行分片。基于前些日子写的《WebSocket的服务端实现》,再加上HTML 5的File API(可参考:HTML5中的文件处理 之 File API,或者W3C File API)和WebStorage。做了一个段断点续传的demo。

代码比较挫,把一个文件分成一个个小片之后,每一次上传都会将已经上传的字节数放到LocalStorage里面。关于LocalStorage里面缓存怎么清,可以参看Chrome - HTML 5 本地存储。如果上传的途中暂停或者直接关掉浏览器。下次上传的时候,就会从那个节点开始上传。

PS:demo操作,请先建立WS连接之后,再选择文件上传

代码请笑纳:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<html>
<head>
    <title>使用WebSocket实现断点续传文件</title>
    <meta charset="utf-8">
</head>
<script type="text/javascript" src="demo.js"></script>
 
<body onload="init();">
<button onclick="webSocketConn();">创建连接</button>(step1)
<div class="row">
      <label for="fileToUpload">Select a File to Upload</label>
      <input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected();"/>(step2)
</div>
<div id="fileName"></div>
<div id="fileSize"></div>
<div id="fileType"></div>
<div class="row">
    <button onclick="sendFileName();uploadFile()">上传</button>(step3)
    <button onclick="pauseUpload()">暂停</button>
    &nbsp;<label id="progressNumber"></label>
</div>
<div id="msg" style="max-height: 400px; overflow:auto;min-height: 100px;">
</div>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#######  断点续传  ######
author:linrb
createTime: 2012-08-22
QQ: 569830404
*/
var websocket = null//websocket
var msg = null; //日志
var paragraph = 10240;  //每次分片传输文件的大小 10KB
var blob = null;//  分片数据的载体Blob对象
var file = null; //传输的文件
var startSize,endSize = 0; //分片的始终字节点
var uploadState = 0;  // 0: 无上传/取消, 1: 上传中, 2: 暂停
 
//初始化消息框
function init(){
    msg = document.getElementById("msg");
}
/**
 * 分片上传文件
 */
function uploadFile() {
    if(file){
        //将上传状态设置成1
        uploadState = 1;
        endSize = getLastestUploadEndSize(file);
        var reader = new FileReader();
        reader.onload = function loaded(evt) {
            var ArrayBuffer = evt.target.result;
            websocket.send(ArrayBuffer);
            uploadProgress(endSize);
        };
        if(endSize < file.size){
            //先发送文件名称
            //websocket.send(file.name);
            //处理文件发送(字节)
            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.readAsArrayBuffer(blob);
        }
    }
}
 
//显示处理进程
function uploadProgress(uploadLen) {
    var percentComplete = Math.round(uploadLen * 100 / file.size);
    document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
 
    //保存到LocalStorage一边下次传输,可以记忆起这个断点
    localStorage.setItem(file.lastModifiedDate + "_" + file.name, uploadLen);
     
}
 
//WebSocket连接
function webSocketConn(){
    try{
        var readyState = new Array("正在连接", "已建立连接", "正在关闭连接"
                    , "已关闭连接");
        var host = "ws://localhost:8000";
        websocket = new WebSocket(host);
        websocket.onopen = function(){
            msg.innerHTML += "<p>Socket状态: " + readyState[websocket.readyState] + "</p>";
        };
        websocket.onmessage = function(event){
            //每上传一个分片之后,等待介绍了服务端的提示之后再做下一个分片上传
            if(event.data.indexOf("ok") != -1 && uploadState == 1){
                if(endSize == file.size){
                    localStorage.removeItem(file.lastModifiedDate + "_" + file.name);
                    msg.innerHTML += "<p>上传完成!!</p>";
                    websocket.close();//结束上传
                }else{
                    uploadFile();
                }
            }
        };
        websocket.onclose = function(){
            msg.innerHTML += "<p>Socket状态: " + readyState[websocket.readyState] + "</p>";
        };
        msg.innerHTML += "<p>Socket状态: " + readyState[websocket.readyState] + "</p>";
    }catch(exception){
        msg.innerHTML += "<p>有错误发生</p>";
        return;
    }
}
 
/*
暂停上传
*/
function pauseUpload(){
    uploadState = 2;
}
 
/**
 * 从localStorage检查最后一次上传的字节
 */
function getLastestUploadEndSize(uploadFile){
    var lastestLen = localStorage.getItem(uploadFile.lastModifiedDate + "_" + uploadFile.name);
    if(lastestLen){
        return parseInt(lastestLen);
    }else{
        return 0;
    }
}
 
 
/*
    发送文件名
*/
function sendFileName(){
    websocket.send(file.name);
}
/**
 * 选择文件之后触发事件
 */
function fileSelected() {
  file = document.getElementById('fileToUpload').files[0];
  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';
 
    document.getElementById('fileName').innerHTML = 'Name: ' + file.name;
    document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize;
    document.getElementById('fileType').innerHTML = 'Type: ' + file.type;
  }
}

服务端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
package fileUpload;
 
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.security.MessageDigest;
 
 
 
public class UploadServer {
    private int port = 8000;
    private ServerSocket serverSocket;
 
    public UploadServer() throws IOException {
        serverSocket = new ServerSocket(port);
        System.out.println("服务器启动");
    }
 
    private void service() {
        Socket socket = null;
        while (true) {
            try {
                socket = serverSocket.accept();
                Thread workThread = new Thread(new Handler(socket));
                workThread.start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
 
    class Handler implements Runnable {
        private Socket socket;
        private boolean hasHandshake = false;
        Charset charset = Charset.forName("UTF-8"); 
        private File file = null;
        private FileOutputStream fileOut = null;
         
        public Handler(Socket socket) {
            this.socket = socket;
        }
 
        private PrintWriter getWriter(Socket socket) throws IOException {
            OutputStream socketOut = socket.getOutputStream();
            return new PrintWriter(socketOut, true);
        }
 
 
        public String echo(String msg) {
            return "echo:" + msg;
        }
 
        public void run() {
             
            try {
                System.out.println("New connection accepted"
                        + socket.getInetAddress() + ":" + socket.getPort());
                InputStream in = socket.getInputStream();
                 
                PrintWriter pw = getWriter(socket);
                //读入缓存
                byte[] buf = new byte[1024];
                //读到字节
                int len = in.read(buf, 0, 1024);
                //读到字节数组
                byte[] res = new byte[len];
                System.arraycopy(buf, 0, res, 0, len);
                String key = new String(res);
                if(!hasHandshake && key.indexOf("Key") > 0){
                    key = key.substring(0, key.indexOf("==") + 2);
                    key = key.substring(key.indexOf("Key") + 4, key.length()).trim();
                    key+= "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
                    MessageDigest md = MessageDigest.getInstance("SHA-1"); 
                    md.update(key.getBytes("utf-8"), 0, key.length());
                    byte[] sha1Hash = md.digest(); 
                        sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder(); 
                    key = encoder.encode(sha1Hash); 
                    pw.println("HTTP/1.1 101 Switching Protocols");
                    pw.println("Upgrade: websocket");
                    pw.println("Connection: Upgrade");
                    pw.println("Sec-WebSocket-Accept: " + key);
                    pw.println();
                    pw.flush();
                    hasHandshake = true;
                     
                    //接收数据
                    byte[] first = new byte[1];
                        int read = in.read(first, 0, 1);
                        while(read > 0){
                            int b = first[0] & 0xFF;
                            //boolean fin = (b & 0x80) > 0;
                           // int rsv = (b & 0x70) >>> 4;
                            byte opCode = (byte) (b & 0x0F);
                             
                            if(opCode == 8){
                            socket.getOutputStream().close();
                            file = null;
                            fileOut.flush();
                            fileOut.close();
                            fileOut = null;
                            break;
                            }
                            b = in.read();
                            int payloadLength = b & 0x7F;
                            if (payloadLength == 126) {
                                byte[] extended = new byte[2];
                                in.read(extended, 0, 2);
                                int shift = 0;
                                payloadLength = 0;
                            for (int i = extended.length - 1; i >= 0; i--) {
                                payloadLength = payloadLength + ((extended[i] & 0xFF) << shift);
                                shift += 8;
                            }
 
                        } else if (payloadLength == 127) {
                            byte[] extended = new byte[8];
                            in.read(extended, 0, 8);
                            int shift = 0;
                            payloadLength = 0;
                            for (int i = extended.length - 1; i >= 0; i--) {
                                payloadLength = payloadLength + ((extended[i] & 0xFF) << shift);
                                shift += 8;
                            }
                        }
                         
                        //掩码
                        byte[] mask = new byte[4];
                        in.read(mask, 0, 4);
                        int readThisFragment = 1;
                        ByteBuffer byteBuf = ByteBuffer.allocate(payloadLength);
                        while(payloadLength > 0){
                             int masked = in.read();
                             masked = masked ^ (mask[(int) ((readThisFragment - 1) % 4)] & 0xFF);
                             byteBuf.put((byte) masked);
                             payloadLength--;
                             readThisFragment++;
                        }
                        byteBuf.flip();
                        if(opCode == 1){
                            getChar(byteBuf.array());
                        }else
                            outFile(byteBuf.array());
                        in.read(first, 0, 1);
                    }
                     
                }
                in.close();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (socket != null)
                        socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
         
        private void responseClient(boolean finalFragment) throws IOException {
            ByteBuffer byteBuf = ByteBuffer.allocate(10);
            byteBuf.put("ok".getBytes("UTF-8"));
            OutputStream out = socket.getOutputStream();
            int first = 0x00;
            //是否是输出最后的WebSocket响应片段,默认
            if (finalFragment) {
                first = first + 0x80;
                first = first + 0x1;
            }
            out.write(first);
             
 
            if (byteBuf.limit() < 126) {
                out.write(byteBuf.limit());
            } else if (byteBuf.limit() < 65536) {
                out.write(126);
                out.write(byteBuf.limit() >>> 8);
                out.write(byteBuf.limit() & 0xFF);
            } else {
                // Will never be more than 2^31-1
                out.write(127);
                out.write(0);
                out.write(0);
                out.write(0);
                out.write(0);
                out.write(byteBuf.limit() >>> 24);
                out.write(byteBuf.limit() >>> 16);
                out.write(byteBuf.limit() >>> 8);
                out.write(byteBuf.limit() & 0xFF);
 
            }
 
            // Write the content
            out.write(byteBuf.array(), 0, byteBuf.limit());
            out.flush();
        }
         
        /**
         * 方法说明:
         * @开发:linrb
         * @创建时间:2012-8-21
         * @param array
         * @throws IOException
         */
        private void getChar(byte[] array) throws IOException {
            ByteArrayInputStream  byteIn = new ByteArrayInputStream(array);
            InputStreamReader reader = new InputStreamReader(byteIn, charset.newDecoder());
            int b = 0;
            String res = "";
            try {
                while((b = reader.read()) > 0){
                    res += (char)b;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            file = new File("C:/" + res);
        }
 
        /**
         * 方法说明:
         * @开发:linrb
         * @创建时间:2012-8-14
         * @param array
         * @throws IOException
         */
        private void outFile(byte[] array) throws IOException {
            if(fileOut == null){
                fileOut = new FileOutputStream(file, true);
            }
            fileOut.write(array);
            responseClient(true);
        }
    }
 
    public static void main(String[] args) throws IOException {
        new UploadServer().service();
    }
}

HTML 5 断点续上传的更多相关文章

  1. iOS通过切片仿断点机制上传文件

    项目开发中,有时候我们需要将本地的文件上传到服务器,简单的几张图片还好,但是针对iPhone里面的视频文件进行上传,为了用户体验,我们有必要实现断点上传.其实也不是真的断点,这里我们只是模仿断点机制. ...

  2. C#使用七牛云存储上传下载文件、自定义回调

    项目需要将音视频文件上传服务器,考虑并发要求高,通过七牛来实现. 做了一个简易的压力测试,同时上传多个文件,七牛自己应该有队列处理并发请求,我无论同时提交多少个文件,七牛是批量一个个排队处理了. 一个 ...

  3. Linux下七牛云存储qrsync命令行上传同步工具

    原址:https://m.aliyun.com/yunqi/ziliao/54370 VPS数据备份是一个重要的工作,之前在文章:使用七牛云存储自动备份VPS数据分享过使用七牛云存储提供的工具QRSB ...

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

    终端实现大文件上传一直都是比较难的技术,其中涉及到后端与前端的交互,稳定性和流量大小,而且实现原理每个人都有自己的想法,后端主流用的比较多的是Http来实现,因为大多实现过断点下载.但稳定性不能保证, ...

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

    实现TCP断点上传,后台C#服务实现接收 终端实现大文件上传一直都是比较难的技术,其中涉及到后端与前端的交互,稳定性和流量大小,而且实现原理每个人都有自己的想法,后端主流用的比较多的是Http来实现, ...

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

    断点上传能够防止意外情况导致上传一半的文件下次上传时还要从头下载,网上有很多关于断点的实现,这篇文章只是从前到后完整的记录下一个可用的实例,由于生产环境要求不高,而且就是提供给一两个人用,所以我简化了 ...

  7. 【翻译】tus----一个可续传文件上传的开放协议

    tus tus是一个可续穿文件上传协议,它以Http协议为载体,统一了一个文件断点续传的标准. 这篇文章翻译自https://tus.io/ 目前该协议版本信息如下: Version: 1.0.0 ( ...

  8. Spring Boot 2.x(十六):玩转vue文件上传

    为什么使用Vue-Simple-Uploader 最近用到了Vue + Spring Boot来完成文件上传的操作,踩了一些坑,对比了一些Vue的组件,发现了一个很好用的组件--Vue-Simple- ...

  9. Android客户端实现七牛云存储文件上传

    1.简单文件上传  上传模型如下. 1.1获得Token 不管是简单文件上传,还是分片上传.断点续传 都需要首先访问服务器,以获得上传凭证信息Token..用于测试时,可以用本地模拟Token信息(有 ...

随机推荐

  1. InetAddress问题

    InetAddress的方法 当输入InetAddress.getByAddress(new byte[]{127.0.0.1})的时候不会报错, 但是ip的各段值是0-255,当new byte[] ...

  2. Quartz 定时邮件发送多个备份文件

    项目代码 pom.xml 文件Quartz 的包是整个项目不可缺少的 <properties> <!-- Spring的版本 --> <springframework.v ...

  3. python3中的编解码

    #一个知识点是:python3中有两种字符串数据类型:str类型和 bytes类型:sty类型存储unicode数据,bytes类型存储bytes数据 #当我们在word上编辑文件的时候,数据保存之前 ...

  4. hdu3436 splaytree树模拟队列+离散化缩点

    数据较大,需要先把每个top不会操作到的段缩成一个点,记录其开始和结束的位置,和top能操作到的点一起建立一颗伸展树模拟 然后就是普通的队列模拟操作 /* 不会被top操作到的区间就缩点 通过spla ...

  5. js面向对象 下

    // 声明对象的方法 一  (通过常量直接赋值) var xiaoming = {//声明一个对象(直接通过一个常量xiaoming用{}赋值的方式声明) name: '小明', //对象的一个属性 ...

  6. Android SDK安装及配置模拟器

    环境搭建 1.安装JDK 2.下载Android sdk exe格式和zip格式都可以 3.安装installer_r24.4.1-windows.exe文件,里面有两个应用程序: "SDK ...

  7. 基于GTID环境的数据恢复

    下面说一个线上环境的数据恢复案例,线上环境误操作的事情,随时都有可能发生的,这时候运维DBA或者DBA会想,没人会傻到把数据库干掉的吧?又或者没有会闲得蛋痛删除了几条数据又想恢复这么无聊吧?适适这样的 ...

  8. Bootstrap表格中,thead固定,tbody有垂直滚动条

    1.html源码:这里的table是使用的vue写法,实际生成的表格和一个一个写的tr th td无异 <div class="panel-body no-padding"& ...

  9. python 全栈开发,Day50(Javascript简介,第一个JavaScript代码,数据类型,运算符,数据类型转换,流程控制,百度换肤,显示隐藏)

    一.Javascript简介 Web前端有三层: HTML:从语义的角度,描述页面结构 CSS:从审美的角度,描述样式(美化页面) JavaScript:从交互的角度,描述行为(提升用户体验) Jav ...

  10. List遍历三种方法:1.for 2.增强性for 3.迭代器

    package chapter09; import java.util.ArrayList;import java.util.Iterator;import java.util.List; /* * ...