断点上传,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. python下的socket常用方法举例

    python下的socket 1.简单的server和client端的socket代码 server.py: #!/usr/bin/env python #_*_ coding:utf-8 _*_ i ...

  2. Ex 6_5棋子放置问题_第八次作业

    题目貌似有问题 (b) 子问题定义: 设maxValue[i][j]为棋盘的前i行中最后一行为i时第i行按照第j种放置方式放置时得到的最大覆盖值,comp[i][j]为第i种放置方式与第j种放置方式是 ...

  3. 擅于使用JS的eval方法

    样例如下: var appsDetails = {“app1”:"", “app2”:"", “app3”:"", “app4”:" ...

  4. Go语言规格说明书 之 类型(Types)

    go version go1.11 windows/amd64 本文为阅读Go语言中文官网的规则说明书(https://golang.google.cn/ref/spec)而做的笔记,完整的介绍Go语 ...

  5. ios如何实现静音模式下声音仍然可以外放

    AVAudioSession *audioSession = [AVAudioSession sharedInstance]; [audioSession setCategory:AVAudioSes ...

  6. 性能测试二十一:环境部署之mysql

    在正常工作中,mysql应该部署到 一台独立的服务器上,不与tomcat共用服务器,由于成本原因,现部署到一起 为避免出错引起麻烦,先备份: 一:环境清理:先卸载系统自带的mysql 停止mysql: ...

  7. python接口自动化测试十一:传参数:data与json

    # 传json参数 import requests url = 'xxxxxxxx' body = {     'xxx': 'xxx',     'xxx': 'xxx' } # body是json ...

  8. 《剑指offer》-找到数组中重复的数字

    题目描述 在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输入长度为 ...

  9. Could not find com.android.tools.build:aapt2:3.2.0-alpha14-4748712.

    https://blog.csdn.net/lx6101989/article/details/80334232 android studio 升级到了3.0 取消了apt 报了这个错 在最上级的bu ...

  10. VMvare虚拟机如何删除安装的ubuntu操作系统

    VMvare虚拟机如何删除安装的ubuntu操作系统呢??? 这个问题其实在我刚开始接触虚拟机和ubuntu操作系统的时候对于如何删除操作系统是一件很苦恼的事情,因为按照书本的步骤,根本看不懂如何操作 ...