热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

HTML5文件域+FileReader分段读取文件并上传(七)WebSocket

一、单文件上传实例

HTML:

<div class="container">
    <div class="panel panel-default">
        <div class="panel-heading">分段读取文件:div>
        <div class="panel-body">
            <input type="file" id="file" /><br />
            <input type="button" value="中止" onclick="stop();" />
            <input type="button" value="继续" onclick="containue();" />
            <progress id="progressOne" style="width:400px;" max="100" value="0">progress>
            <blockquote id="Status" style="word-break:break-all;">blockquote>
        div>
    div>
div>

JS:

/*
    * 测试WebSocket上传
    * 本地浏览器上传速度测试单个文件,上传速度IE>FF>Google(Google浏览器慢相当多)
    */
var fileBox = document.getElementById('file');
var reader = null;  //读取操作对象
var step = 1024 * 256;  //每次读取文件大小 ,字节数
var cuLoaded = 0; //当前已经读取总数
var file = null; //当前读取的文件对象
var enableRead = true;//标识是否可以读取文件
var total = 0;        //记录当前文件总字节数
var startTime = null; //标识开始上传时间
fileBox.Onchange= function () {
    //获取文件对象
    file = this.files[0];
    total = file.size;
    console.info("文件大小:" + file.size);
    if (ws == null) {
        if (window.confirm('建立与服务器链接失败,确定重试链接吗')) {
            createSocket(function () {
                bindReader();
            });
        }
        return;
    }
    bindReader();
}
//绑定reader
function bindReader() {
    cuLoaded = 0;
    startTime = new Date();
    enableRead = true;
    reader = new FileReader();
    //读取一段成功
    reader.Onload= function (e) {
        console.info('读取总数:' + e.loaded);
        if (enableRead == false)
            return false;
        //根据当前缓冲区来控制客户端读取速度
        if (ws.bufferedAmount > step * 10) {
            setTimeout(function () {
                //继续读取
                console.log('--------------》进入等待');
                loadSuccess(e.loaded);
            }, 3);
        } else {
            //继续读取
            loadSuccess(e.loaded);
        }
    }
    //开始读取
    readBlob();
}
//读取文件成功处理
function loadSuccess(loaded) {
    //将分段数据上传到服务器
    var blob = reader.result;
    //使用WebSocket 服务器发送数据
    if (cuLoaded == 0) //发送文件名
        ws.send(file.name);
    ws.send(blob);
    //如果没有读完,继续
    cuLoaded += loaded;
    if (cuLoaded < total) {
        readBlob();
    } else {
        console.log('总共上传:' + cuLoaded + ',总共用时:' + (new Date().getTime() - startTime.getTime()) / 1000);
    }
    //显示结果进度
    var percent = (cuLoaded / total) * 100;
    document.getElementById('Status').innerText = percent;
    document.getElementById('progressOne').value = percent;
}
//指定开始位置,分块读取文件
function readBlob() {
    //指定开始位置和结束位置读取文件
    var blob = file.slice(cuLoaded, cuLoaded + step);
    reader.readAsArrayBuffer(blob);
}
//中止
function stop() {
    //中止读取操作
    console.info('中止,cuLoaded:' + cuLoaded);
    enableRead = false;
    reader.abort();
}
//继续
function containue() {
    console.info('继续,cuLoaded:' + cuLoaded);
    enableRead = true;
    readBlob();
}
var ws = null;
//创建和服务器的WebSocket 链接
function createSocket(onSuccess) {
    var url = 'ws://localhost:55373/ashx/upload3.ashx';
    ws = new WebSocket(url);
    ws.onopen = function () {
        console.log('connected成功');
        if (onSuccess)
            onSuccess();
    }
    ws.onmessage = function (e) {
        var data = e.data;
        if (isNaN(data) == false) {
            //console.log('当前上传成功:' + data);
        } else {
            console.info(data);
        }
    }
    ws.onclose = function (e) {
        //中止客户端读取
        stop();
        console.log('链接断开');
    }
    ws.onerror = function (e) {
        //中止客户端读取
        stop();
        console.info(e);
        console.log('传输中发生异常');
    }
}
//页面加载完建立链接
createSocket();
服务器后台处理:
    public void ProcessRequest(HttpContext context)
    {
        //处理WebSocket 请求
        context.AcceptWebSocketRequest(DoWork);
    }
    /// 
    /// 委托处理函数定义
    /// 
    /// 当前WebSocket上下文
    /// 
    public async Task DoWork(AspNetWebSocketContext context)
    {
        //1.获取当前WebSocket 对象
        WebSocket socket = context.WebSocket;
        string filename = "";
        //2.监视相应
        while (true)
        {
            /*
                * 此处缓存数组指定读取客户端数据的长度
                * 如果客户端发送数据超过当前缓存区,则会读取多次
                */
            ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[1024 * 256]);
            //接收客户端信息
            CancellationToken token;
            WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, token);
            if (socket.State == WebSocketState.Open)
            {
                //判断是否已经到了最后
                int curLength = Math.Min(buffer.Array.Length, result.Count);
                //判断用户传入的类型进行处理
                if (result.MessageType == WebSocketMessageType.Text)
                {
                    string msg = Encoding.UTF8.GetString(buffer.Array, 0, curLength);
                    filename = msg;
                    buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes("接收文件名成功:" + filename));
                    await socket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
                }
                else if (result.MessageType == WebSocketMessageType.Binary)
                {
                    //创建并保存文件,如果上传成功,返回当前接收到的文件大小
                    string msg = SaveFile(filename, buffer, curLength);
                    buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(curLength.ToString()));
                    await socket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
                }
            }
            else { break; }
        }
    }
    /// 
    /// 追加二进制数据到文件
    /// 
    public string SaveFile(string file, ArraySegment<byte> buffer, int Length)
    {
        //去除文件名中的前后空格
        file = file.Trim();
        string fullname = @"F:\Javascript_Solution\H5Solition\UploadWebForm\content\" + file;
        try
        {
            FileStream fs = new FileStream(fullname, FileMode.Append, FileAccess.Write);
            try
            {
                byte[] result = buffer.ToArray();
                fs.Write(result, 0, Length);
            }
            finally
            {
                fs.Close();
            }
            return "保存文件成功";
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }

 


本地浏览器上传速度测试单个文件,上传速度IE>FF>Google(Google浏览器慢相当多)
原因:每次send发送数据的时候Google浏览器发送的数据量相对较小

HTML5 文件域+FileReader 分段读取文件并上传(七)-WebSocketHTML5 文件域+FileReader 分段读取文件并上传(七)-WebSocketHTML5 文件域+FileReader 分段读取文件并上传(七)-WebSocket

分段上传文件(六):http://www.cnblogs.com/tianma3798/p/5845291.html
分段读取文件(五):http://www.cnblogs.com/tianma3798/p/5841584.html

分段读取文件(四):http://www.cnblogs.com/tianma3798/p/5839869.html

 读取文件三:http://www.cnblogs.com/tianma3798/p/5839810.html

读取文件二:http://www.cnblogs.com/tianma3798/p/5839791.html

读取文件一:http://www.cnblogs.com/tianma3798/p/4355949.html

            
                 
                
推荐阅读
  • JavaScript和HTML之间的交互是经由过程事宜完成的。事宜:文档或浏览器窗口中发作的一些特定的交互霎时。能够运用侦听器(或处置惩罚递次来预订事宜),以便事宜发作时实行相应的 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了作者在开发过程中遇到的问题,即播放框架内容安全策略设置不起作用的错误。作者通过使用编译时依赖注入的方式解决了这个问题,并分享了解决方案。文章详细描述了问题的出现情况、错误输出内容以及解决方案的具体步骤。如果你也遇到了类似的问题,本文可能对你有一定的参考价值。 ... [详细]
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 使用eclipse创建一个Java项目的步骤
    本文介绍了使用eclipse创建一个Java项目的步骤,包括启动eclipse、选择New Project命令、在对话框中输入项目名称等。同时还介绍了Java Settings对话框中的一些选项,以及如何修改Java程序的输出目录。 ... [详细]
  • EPPlus绘制刻度线的方法及示例代码
    本文介绍了使用EPPlus绘制刻度线的方法,并提供了示例代码。通过ExcelPackage类和List对象,可以实现在Excel中绘制刻度线的功能。具体的方法和示例代码在文章中进行了详细的介绍和演示。 ... [详细]
  • 单页面应用 VS 多页面应用的区别和适用场景
    本文主要介绍了单页面应用(SPA)和多页面应用(MPA)的区别和适用场景。单页面应用只有一个主页面,所有内容都包含在主页面中,页面切换快但需要做相关的调优;多页面应用有多个独立的页面,每个页面都要加载相关资源,页面切换慢但适用于对SEO要求较高的应用。文章还提到了两者在资源加载、过渡动画、路由模式和数据传递方面的差异。 ... [详细]
  • 本文介绍了pack布局管理器在Perl/Tk中的使用方法及注意事项。通过调用pack()方法,可以控制部件在显示窗口中的位置和大小。同时,本文还提到了在使用pack布局管理器时,应注意将部件分组以便在水平和垂直方向上进行堆放。此外,还介绍了使用Frame部件或Toplevel部件来组织部件在窗口内的方法。最后,本文强调了在使用pack布局管理器时,应避免在中间切换到grid布局管理器,以免造成混乱。 ... [详细]
  • 本文详细介绍了Android中的坐标系以及与View相关的方法。首先介绍了Android坐标系和视图坐标系的概念,并通过图示进行了解释。接着提到了View的大小可以超过手机屏幕,并且只有在手机屏幕内才能看到。最后,作者表示将在后续文章中继续探讨与View相关的内容。 ... [详细]
author-avatar
香樟树1016
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有