zoukankan      html  css  js  c++  java
  • HTML5 文件域+FileReader 分段读取文件并上传到服务器(六)

    说明:使用Ajax方式上传,文件不能过大,最好小于三四百兆,因为过多的连续Ajax请求会使后台崩溃,获取InputStream中数据会为空,尤其在Google浏览器测试过程中。

    1.简单分段读取文件为Blob,ajax上传到服务器

    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">分段读取文件:</div>
            <div class="panel-body">
                <input type="file" id="file" />
                <blockquote style="word-break:break-all;"></blockquote>
            </div>
        </div>
    </div>

    JS:

    /*
    * 分段读取文件为blob ,并使用ajax上传到服务器
    * 分段上传exe文件会抛出异常
    */
    var fileBox = document.getElementById('file');
    file.onchange = function () {
        //获取文件对象
        var file = this.files[0];
        var reader = new FileReader();
        var step = 1024 * 1024;
        var total = file.size;
        var cuLoaded = 0;
        console.info("文件大小:" + file.size);
        var startTime = new Date();
        //读取一段成功
        reader.onload = function (e) {
            //处理读取的结果
            var loaded = e.loaded;
            //将分段数据上传到服务器
            uploadFile(reader.result, cuLoaded, function () {
                console.info('loaded:' + cuLoaded + 'current:' + loaded);
                //如果没有读完,继续
                cuLoaded += loaded;
                if (cuLoaded < total) {
                    readBlob(cuLoaded);
                } else {
                    console.log('总共用时:' + (new Date().getTime() - startTime.getTime()) / 1000);
                    cuLoaded = total;
                }
            });
        }
        //指定开始位置,分块读取文件
        function readBlob(start) {
            //指定开始位置和结束位置读取文件
            //console.info('start:' + start);
            var blob = file.slice(start, start + step);
            reader.readAsArrayBuffer(blob);
        }
        //开始读取
        readBlob(0);
        //关键代码上传到服务器
        function uploadFile(result, startIndex, onSuccess) {
            var blob = new Blob([result]);
            //提交到服务器
            var fd = new FormData();
            fd.append('file', blob);
            fd.append('filename', file.name);
            fd.append('loaded', startIndex);
            var xhr = new XMLHttpRequest();
            xhr.open('post', '../ashx/upload2.ashx', true);
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    // var data = eval('(' + xhr.responseText + ')');
                    console.info(xhr.responseText);
                    if (onSuccess)
                        onSuccess();
                }
            }
            //开始发送
            xhr.send(fd);
        }
    }

    后台代码:

    /// <summary>
    /// upload2 的摘要说明
    /// </summary>
    public class upload2 : IHttpHandler
    {
        LogHelper.LogHelper _log = new LogHelper.LogHelper();
        int totalCount = 0;
        public void ProcessRequest(HttpContext context)
        {
            HttpContext _Context = context;
            //接收文件
            HttpRequest req = _Context.Request;
            if (req.Files.Count <= 0)
            {
                WriteStr("获取服务器上传文件失败");
                return;
            }
            HttpPostedFile _file = req.Files[0];
            //获取参数
            // string ext = req.Form["extention"];
            string filename = req.Form["filename"];
            //如果是int 类型当文件大的时候会出问题 最大也就是 1.9999999990686774G
            int loaded = Convert.ToInt32(req.Form["loaded"]);
            totalCount += loaded;
    
            string newname = @"F:JavaScript_SolutionH5SolitionH5SolitionContentTempFile";
            newname += filename;
            //接收二级制数据并保存
            Stream stream = _file.InputStream;
            if (stream.Length <= 0)
                throw new Exception("接收的数据不能为空");
            byte[] dataOne = new byte[stream.Length];
            stream.Read(dataOne, 0, dataOne.Length);
            FileStream fs = new FileStream(newname, FileMode.Append, FileAccess.Write, FileShare.Read, 1024);
            try
            {
                fs.Write(dataOne, 0, dataOne.Length);
            }
            finally
            {
                fs.Close();
                stream.Close();
            }
            _log.WriteLine((totalCount + dataOne.Length).ToString());
            WriteStr("分段数据保存成功");
        }
        private void WriteStr(string str)
        {
            HttpContext.Current.Response.Write(str); 
        }
        public bool IsReusable
        {
            get
            {
                return true;
            }
        }

    2.分段读取文件为blob ,并使用ajax上传到服务器,追加中止、继续功能操作

    <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();" />&emsp;
                <input type="button" value="继续" onclick="containue();" />
                <br />
                <progress id="progressOne" max="100" value="0" style="400px;"></progress>
                <blockquote id="Status" style="word-break:break-all;"></blockquote>
            </div>
        </div>
    </div>

    JS:

    /*
    * 分段读取文件为blob ,并使用ajax上传到服务器
    * 使用Ajax方式提交上传数据文件大小应该有限值,最好500MB以内
    * 原因短时间过多的ajax请求,Asp.Net后台会崩溃获取上传的分块数据为空
    * 取代方式,长连接或WebSocket
    */
    var fileBox = document.getElementById('file');
    var reader = null;  //读取操作对象
    var step = 1024 * 1024 * 3.5;  //每次读取文件大小
    var cuLoaded = 0; //当前已经读取总数
    var file = null; //当前读取的文件对象
    var enableRead = true;//标识是否可以读取文件
    fileBox.onchange = function () {
        //获取文件对象
        file = this.files[0];
        var total = file.size;
        console.info("文件大小:" + file.size);
        var startTime = new Date();
        reader = new FileReader();
        //读取一段成功
        reader.onload = function (e) {
            //处理读取的结果
            var result = reader.result;
            var loaded = e.loaded;
            if (enableRead == false)
                return false;
            //将分段数据上传到服务器
            uploadFile(result, cuLoaded, function () {
                console.info('loaded:' + cuLoaded + '----current:' + loaded);
                //如果没有读完,继续
                cuLoaded += loaded;
                if (cuLoaded < total) {
                    readBlob(cuLoaded);
                } else {
                    console.log('总共用时:' + (new Date().getTime() - startTime.getTime()) / 1000);
                    cuLoaded = total;
                }
                //显示结果进度
                var percent = (cuLoaded / total) * 100;
                document.getElementById('Status').innerText = percent;
                document.getElementById('progressOne').value = percent;
            });
        }
        //开始读取
        readBlob(0);
        //关键代码上传到服务器
        function uploadFile(result, startIndex, onSuccess) {
            var blob = new Blob([result]);
            //提交到服务器
            var fd = new FormData();
            fd.append('file', blob);
            fd.append('filename', file.name);
            fd.append('loaded', startIndex);
            var xhr = new XMLHttpRequest();
            xhr.open('post', '../ashx/upload2.ashx', true);
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    if (onSuccess)
                        onSuccess();
                } else if (xhr.status == 500) {
                    //console.info('请求出错,' + xhr.responseText);
                    setTimeout(function () {
                        containue();
                    }, 1000);
                }
            }
            //开始发送
            xhr.send(fd);
        }
    }
    //指定开始位置,分块读取文件
    function readBlob(start) {
        //指定开始位置和结束位置读取文件
        var blob = file.slice(start, start + step);
        reader.readAsArrayBuffer(blob);
    }
    //中止
    function stop() {
        //中止读取操作
        console.info('中止,cuLoaded:' + cuLoaded);
        enableRead = false;
        reader.abort();
    }
    //继续
    function containue() {
        console.info('继续,cuLoaded:' + cuLoaded);
        enableRead = true;
        readBlob(cuLoaded);
    }

    后台代码同上

    3.分段读取文件为二进制数组 ,并使用ajax上传到服务器

     使用二进制数组传递的方式,效率特别低,最终文件还与原始大小有些偏差

    HTML内容同上

    JS:

    /*
        * 分段读取文件为二进制数组 ,并使用ajax上传到服务器
        * 使用二进制数组传递的方式,效率特别低,最终文件还与原始大小有些偏差
        */
    var fileBox = document.getElementById('file');
    var reader = new FileReader(); //读取操作对象
    var step = 1024 * 1024;  //每次读取文件大小
    var cuLoaded = 0; //当前已经读取总数
    var file = null; //当前读取的文件对象
    var enableRead = true;//标识是否可以读取文件
    fileBox.onchange = function () {
        //获取文件对象
        if (file == null) //如果赋值多次会有丢失数据的可能
            file = this.files[0];
        var total = file.size;
        console.info("文件大小:" + file.size);
        var startTime = new Date();
        //读取一段成功
        reader.onload = function (e) {
            //处理读取的结果
            var result = reader.result;
            var loaded = e.loaded;
            if (enableRead == false)
                return false;
            //将分段数据上传到服务器
            uploadFile(result, cuLoaded, function () {
                console.info('loaded:' + cuLoaded + '----current:' + loaded);
                //如果没有读完,继续
                cuLoaded += loaded;
                if (cuLoaded < total) {
                    readBlob(cuLoaded);
                } else {
                    console.log('总共用时:' + (new Date().getTime() - startTime.getTime()) / 1000);
                    cuLoaded = total;
                }
                //显示结果进度
                var percent = (cuLoaded / total) * 100;
                document.getElementById('Status').innerText = percent;
                document.getElementById('progressOne').value = percent;
            });
        }
        //开始读取
        readBlob(0);
        //关键代码上传到服务器
        function uploadFile(result, startIndex, onSuccess) {
            var array = new Int8Array(result);
            console.info(array.byteLength);
            //提交到服务器
            var fd = new FormData();
            fd.append('file', array);
            fd.append('filename', file.name);
            fd.append('loaded', startIndex);
            var xhr = new XMLHttpRequest();
            xhr.open('post', '../ashx/upload3.ashx', true);
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    // console.info(xhr.responseText);
                    if (onSuccess)
                        onSuccess();
                } else if (xhr.status == 500) {
                    console.info('服务器出错');
                    reader.abort();
                }
            }
            //开始发送
            xhr.send(fd);
        }
    }
    //指定开始位置,分块读取文件
    function readBlob(start) {
        //指定开始位置和结束位置读取文件
        var blob = file.slice(start, start + step);
        reader.readAsArrayBuffer(blob);
    }
    //中止
    function stop() {
        //中止读取操作
        console.info('中止,cuLoaded:' + cuLoaded);
        enableRead = false;
        reader.abort();
    }
    //继续
    function containue() {
        console.info('继续,cuLoaded:' + cuLoaded);
        enableRead = true;
        readBlob(cuLoaded);
    }

    后台代码:

    /// <summary>
    /// upload3 的摘要说明
    /// </summary>
    public class upload3 : IHttpHandler
    {
        LogHelper.LogHelper _log = new LogHelper.LogHelper();
        int totalCount = 0;
        public void ProcessRequest(HttpContext context)
        {
            HttpContext _Context = context;
            //接收文件
            HttpRequest req = _Context.Request;
            string data = req.Form["file"];
            //转换方式一
            //int[] intData = data.Split(',').Select(q => Convert.ToInt32(q)).ToArray();
            //byte[] dataArray = intData.ToList().ConvertAll(x=>(byte)x).ToArray();
            //转换方式二
            byte[] dataArray = data.Split(',').Select(q => int.Parse(q)).Select(q => (byte)q).ToArray();
            //获取参数
            string filename = req.Form["filename"];
            //如果是int 类型当文件大的时候会出问题 最大也就是 1.9999999990686774G
            int loaded = Convert.ToInt32(req.Form["loaded"]);
            totalCount += loaded;
            string newname = @"F:JavaScript_SolutionH5SolitionH5SolitionContentTempFile";
            newname += filename;
            try
            {
                // 接收二级制数据并保存
                byte[] dataOne = dataArray;
                FileStream fs = new FileStream(newname, FileMode.Append, FileAccess.Write, FileShare.Read, 1024);
                try
                {
                    fs.Write(dataOne, 0, dataOne.Length);
                }
                finally
                {
                    fs.Close();
                }
                _log.WriteLine((totalCount + dataOne.Length).ToString());
                WriteStr("分段数据保存成功");
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        private void WriteStr(string str)
        {
            HttpContext.Current.Response.Write(str);
        }
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
  • 相关阅读:
    How to build Linux system from kernel to UI layer
    Writing USB driver for Android
    Xposed Framework for Android 8.x Oreo is released (in beta)
    Linux Smartphone Operating Systems You Can Install Today
    Librem 5 Leads New Wave of Open Source Mobile Linux Contenders
    GUADEC: porting GNOME to Android
    Librem 5 – A Security and Privacy Focused Phone
    GNOME and KDE Join Librem 5 Linux Smartphone Party
    Purism计划推出安全开源的Linux Librem 5智能手机
    国产系统之殇:你知道的这些系统都是国外的
  • 原文地址:https://www.cnblogs.com/tianma3798/p/5845291.html
Copyright © 2011-2022 走看看