断点上传,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. Spring boot教程mybatis访问MySQL的尝试

    Windows 10家庭中文版,Eclipse,Java 1.8,spring boot 2.1.0,mybatis-spring-boot-starter 1.3.2,com.github.page ...

  2. X-Forwarded-For 的一些理解

    X-Forwarded-For 是一个 HTTP 扩展头部, 主要是为了让 Web 服务器获取访问用户的真实 IP 地址(其实这个真实未必是真实的,后面会说到). 那为什么 Web 服务器只有通过 X ...

  3. PLSQL developer 连接不上64位Oracle 解决办法

    在64位Windows7上安装Oracle后,用PLSQL developer去连接数据库出现报错: Could not load "……\bin\oci.dll" OCIDLL ...

  4. GuzzleHttp 请求设置超时时间

    之前调用一个三方的 WEB API,大量的请求超时,导致 PHP 进程被占用完.整个网站一直报 504. 其中一个优化措施就是对三方 API 调用设置超时时间. use GuzzleHttp\Clie ...

  5. SPLAY,LCT学习笔记(五)

    这一篇重点探讨LCT的应用 例:bzoj 2631 tree2(国家集训队) LCT模板操作之一,利用SPLAY可以进行区间操作这一性质对维护懒惰标记,注意标记下传顺序和如何下传 #include & ...

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

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

  7. 检查Rabbitmq中队列及消息个数,还有清空的方法

    rabbitmqctl list_queues rabbitmqctl purge_queue kafka_queue (不推荐)使用reset方式重置rabbitmq即清空掉rabbitmq所有的队 ...

  8. hdu 1548 升降梯

    题目大意:有一个升降机,它有两个按钮UP和DOWN,给你一些数i表示层数,并且每层对应的Ki,如果按UP按钮,会从第i层升到第i+Ki层:如果按了DOWN则会从第i层降到第i-Ki层:并规定能到的层数 ...

  9. Ajax异步验证登陆或者注册

    首先介绍一个不错的学习Ajax的中文网站:http://www.w3school.com.cn/ajax/index.asp AJAX = 异步 JavaScript 和 XML.详细介绍见上面的网址 ...

  10. Codeforces Round #319 (Div. 2) D - Invariance of Tree

    Invariance of Tree 题目大意:给你一个有1-n组成的序列p,让你构造一棵树,如果节点a和b之间有一条边,则p[a]和p[b]之间也有一条边. 思路:没啥思路,看了题解菜爆. 我们可以 ...