zoukankan      html  css  js  c++  java
  • 使用Html5的WebSocket在浏览器上传文件, 支持多文件和大文件.

    使用websocket上传文件的简单例子: 使用Html5的WebSocket在浏览器上传文件

    上篇文章没有解决的问题就是大文件的上传问题, 而且多文件上传问题也未协调. 所以这篇文章就是解决这两个问题的.

    如果将一个大文件直接读入内存再发送的话, 内存会吃不消, 所以我们把大文件分块传输.  Html5的Fileread方法提供了读取文件部分内容Blob的方法.

    为了保证后台接收到的分块数据的顺序不会乱掉, 我们需要后台确定写入分块数据后再发送下一块数据. 

    在Html端:

    <!DOCTYPE html>
    <html>
    <head>
    <title>WebSocket Chat Client</title>
    <meta charset="utf-8" />
    <script type="text/javascript" src="jquery-1.6.4.min.js"></script>
    <script type="text/javascript" src="jquery.json-2.3.min.js"></script>
    <script type="text/javascript">
    $().ready(
    function() {
    // Check for the various File API support.
                  if (window.File && window.FileReader && window.FileList
    && window.Blob) {
    // Great success! All the File APIs are supported.
    } else {
    alert(
    'The File APIs are not fully supported in this browser.');
    }
    });

    //在消息框中打印内容
    function log(text) {
    $(
    "#log").append(text+"\n");
    }

    //全局的websocket变量
    var ws;
    var paragraph = 10485760;
    var fileList ;
    var file;
    var startSize,endSize = 0;
    var i = 0; j = 0;
    //连接服务器
    $(function() {
    $(
    "#connect").click(function() {
    ws
    = new WebSocket($("#uri").val());
    //连接成功建立后响应
    ws.onopen = function() {
    log(
    "成功连接到" + $("#uri").val());
    }
    //收到服务器消息后响应
    ws.onmessage = function(e) {
    log(
    "服务器说" + e.data + (e.data=="ok"));
    if(e.data == "ok"){
    if(endSize < file.size){
    startSize
    = endSize;
    endSize
    += paragraph ;
    if (file.webkitSlice) {
    var blob = file.webkitSlice(startSize, endSize);
    }
    else if (file.mozSlice) {
    var blob = file.mozSlice(startSize, endSize);
    }
    var reader = new FileReader();
    reader.readAsArrayBuffer(blob);
    reader.onload
    = function loaded(evt) {
    var ArrayBuffer = evt.target.result;
    log(
    "发送文件第" + (i++) + "部分");
    ws.send(ArrayBuffer);
    }
    }
    else{
    startSize
    = endSize = 0;
    i
    = 0;
    log(
    "发送" + file.name +"完毕");
    file
    = fileList[j++];
    if(file.name){
    ws.send(file.name);
    }
    log(
    "发送文件完毕");
    }
    }
    //连接关闭后响应
    ws.onclose = function() {
    log(
    "关闭连接");
    ws
    = null;
    }
    return false;
    }
    });
    });


    $(
    function() {
    $(
    "#sendFileForm").click(function() {
    fileList
    = document.getElementById("file").files;
    file
    = fileList[0];
    ws.send(file.name);
    })
    });

    $(
    function() {
    $(
    "#reset").click(function() {
    $(
    "#log").empty();
    return false;
    });
    });

    </script>
    </head>
    <body>
    <span>Html5功能测试</span>
    <span id="progress">0</span><br>
    <input type="text" id="uri" value="ws://localhost:8887"
    style
    =" 200px;"> <input type="button" id="connect"
    value
    ="Connect"><input type="button" id="disconnect"
    value
    ="Disconnect" disabled="disabled">
    <form >
    <input id="file" type="file" multiple />
    <input type="button" id="sendFileForm" value="测试" />
    <input type="button" id="reset" value="清空消息框" />
    </form>
    <form>
    <textarea id="log" rows="30" cols="100"
    style
    ="font-family: monospace; color: red;"></textarea>
    </form>
    </body>
    </html>

    这里设置了文件大于paragraph (10M)时就会分块发送文件.


    服务器端:

    /**
    * 处理字符串消息
    */
    public void onMessage( WebSocket conn, String message ) {

    System.out.println("文件名" + message);
    //将文件名写入连接对象中,(需要手动修改webSocket类)
    conn.setFileName(message);

    try {
    conn.send("ok");
    } catch (NotYetConnectedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (IllegalArgumentException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    /**
    * 处理二进制消息
    */
    public void onMessage(WebSocket conn, byte[] message) {
    System.out.println("收到二进制流:");
    //将二进制流保存为文件, 文件名从连接对象中取出
    saveFileFromBytes(message, "src/" + conn.getFileName());
    //告诉前台可以继续发送了.
    try {
    conn.send("ok");
    } catch (NotYetConnectedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (IllegalArgumentException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }

    /**
    * 将二进制byte[]数组写入文件中
    *
    @param b byte[]数组
    *
    @param outputFile 文件位置
    *
    @return 成功: true 失败: false
    */
    public static boolean saveFileFromBytes(byte[] b, String outputFile)
    {
    FileOutputStream fstream = null;
    File file = null;
    try
    {
    file = new File(outputFile);
    fstream = new FileOutputStream(file, true);
    fstream.write(b);
    }
    catch (Exception e)
    {
    e.printStackTrace();
    return false;
    }
    finally
    {
    if (fstream != null)
    {
    try
    {
    fstream.close();
    }
    catch (IOException e1)
    {
    e1.printStackTrace();
    }
    }
    }
    return true;
    }


    好了, 顺序发送保证了后台写入的数据也是顺序的, 文件就不会出错了! 搞定!

  • 相关阅读:
    git连接到https服务器时出现“gnutls_handshake() failed”
    Linux内核:通知链 机制
    在Linux驱动中使用notifier通知链
    Linux 内核:RCU机制与使用
    什么是工程师文化?
    在Android源码中查找Java代码中native函数对应的C++实现
    Windows下Qt5程序打包发布
    Android Framework:如何让 App 拿到Power key 值
    Windows 监控小工具
    Windows 远程桌面无法上传文件或者文件夹
  • 原文地址:https://www.cnblogs.com/myfjd/p/2417448.html
Copyright © 2011-2022 走看看