浏览器中处理上传大文件——FileReader.readAsArrayBuffer()方法

这篇具有很好参考价值的文章主要介绍了浏览器中处理上传大文件——FileReader.readAsArrayBuffer()方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.问题点

平常从客户端上传文件到服务器端,只需要读取 input 的 File 对象,然后将其塞到 FormData 对象中,然后使用 ajax 发送到服务器端,服务器端会有配套的读文件和写文件的操作。

现在遇到一个问题,就是在本地一个进程中,浏览器和其他代码间数据的发送,因为不经过 HTTP,这时候只有将文件的信息读取出来,然后通过二进制或是 base64 编码的格式发送。

HTML5 的 FileReader API 可以在浏览器对用户本地文件进行读取,但是在使用的过程中又遇到了新的问题,比如通过 FileReader.readAsDataURL() ,使用时它会读取一整个文件的信息,加载到内存中,50MB 以内的文件基本不会遇到什么问题,但是当文件达到 300MB 甚至是 1G 以上,直接读取一整个文件,会导致内存超出上限,浏览器这时候就会崩溃,因此如果想要处理大的文件,我们只能将大文件切成一块一块的,将其变成小文件后再去处理,FileReader 也提供了相关的 API,即 FileReader.readAsArrayBuffer() ,下面就看一下使用 FileReader.readAsArrayBuffer() 进行切块的处理吧。文章来源地址https://www.toymoban.com/news/detail-677263.html

2.大文件切块处理的思路

  1. 使用 FileReader.readAsArrayBuffer() 读取文件,在读取成功后 result 属性中将包含一个 ArrayBuffer 对象以表示所读取文件的数据。
  2. 对读取到的 ArrayBuffer 对象进行拆分,放到一个数组中
  3. 使用 Promise.all 来顺序的处理拆分后的数组(保证顺序传输)
  4. 使用 Uint8Array 将 ArrayBuffer 拆后后的数组生成 二进制字节数组
  5. 最后将二进制字节数组转为 base64 编码的字符串
  6. 传输的是 base64 编码的字符串,到达目的地后,需要使用 base64 解码,才能得到原始的二进制字节信息
FileReader提供的方法 说明
readAsArrayBuffer(file) 按字节读取文件内容,结果用ArrayBuffer对象表示
readAsBinaryString(file) 按字节读取文件内容,结果为文件的二进制串
readAsDataURL(file) 读取文件内容,结果用data:url的字符串形式表示
readAsText(file,encoding) 按字符读取文件内容,结果用字符串形式表示
abort() 终止文件读取操作
FileReader事件 说明
onloadstart 当读取操作开始时调用
当读取操作开始时调用 在读取数据过程中周期性调用
onabort 当读取操作被中止时调用
onerror 当读取操作发生错误时调用
onload 当读取操作成功完成时调用
onloadend 当读取操作完成时调用,无论成功,失败或取消

3.以下代码实现的功能

  • 在特定区域识别拖拽的文件
  • 有一个配置项:
    小于 20 MB 算小文件,直接整个处理;
    大于 20 MB 算大文件,进行切块处理;
  • 大文件切块后,将依次按照切块的顺序上传
  • 注意事项:最后从浏览器传输文件数据的时候,传输的是 base64 编码的字符串,因此传送到目的地后,需要 base64 解码后再进行操作
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        body {
            width: 100vw;
            height: 100vh;
        }

        .drag-area-container {
            width: 800px;
            height: 800px;
            border: 1px solid #0f0;
        }

        .highlight {
            border: 10px solid #0f0;
        }
    </style>
</head>
<body>
    <div class="drag-area-container">
    </div>

    <script>
        (function() {
            // 禁止浏览器的拖拽默认事件
            var globalDragFile = function() {
                let globalDragArea = document.querySelector('body')

                globalDragArea.addEventListener('dragover',function(e){
                    e.preventDefault()
                })

                globalDragArea.addEventListener('drop', function(e) {
                    e.preventDefault()
                })
            }

            // 识别指定区域的拖动效果
            var localDragFile = function() {
                let localDragArea = document.querySelector('.drag-area-container')

                localDragArea.addEventListener('dragenter',function(e){
                    // 拖动文件到指定区域时,添加高亮
                    localDragArea.classList.add('highlight')
                    e.preventDefault()
                })

                localDragArea.addEventListener('dragover',function(e){
                    e.preventDefault()
                })

                localDragArea.addEventListener('drop', function(e) {
                    e.preventDefault()

                    // 去除高亮
                    localDragArea.classList.remove('highlight')

                    var file = e.dataTransfer.files[0]
                    console.log("file = ", file);
                    uploadFile(file)
                })
            }

            // 处理文件 && 上传文件
            var uploadFile = function(file) {
                // 使用 FileReader 读取文件的数据
                var reader = new FileReader()

                reader.onloadend = function() {
                    var file_result = this.result               // ArrayBuffer 数据对象
                    var file_length = file_result.byteLength

                    // 小于 20 MB 为小文件,则整个读取并上传
                    // 大于 20 MB 为大文件,则需要将它切成小块,分别上传
                    var step = 1024 * 1024 * 20

                    if (file_length < step) {
                        console.log("小文件,直接整个上传 ");
                        handleSmallFile(file_result)
                    } else {
                        console.log("大文件,切块分别上传 ");
                        var block_arr = splitBigFile(file_result, file_length, step)

                        handleBigFile(block_arr).then(function(results) {
                            console.log("大文件,切块上传成功 result = ", results)
                        })
                    }
                }

                reader.readAsArrayBuffer(file)
                /*
                    readAsArrayBuffer()        // 读取完成,result  属性中保存的将是被读取文件的 ArrayBuffer 数据对象。
                    readAsBinaryString()       // 读取完成,result  属性中将包含所读取文件的原始二进制数据。
                    readAsDataURL()            // 读取完成,result 属性中将包含一个 data: URL 格式的 Base64 字符串以表示所读取文件的内容。
                    readAsText()               // 读取完成,result 属性中将包含一个字符串以表示所读取的文件内容。
                */
            }

            var handleSmallFile = function(file_result) {
                // 先读取到 ArrayBuffer,再获取 ArrayBuffer 的 Uint8Array 字节数组形式,最后用 base64 编码字节数组用于传输。
                var unit8_data = new Uint8Array(file_result)            // 提取二进制字节数组,使用 Uint8Array 表示
                var base64_data = binary2base64(unit8_data)             // base64 编码

                console.log("==== handle upload start ====");
                console.log("data = ", base64_data);
                console.log("==== handle upload end ====");
            }

            // 根据指定的 step 大小,切出来指定的 step 大小的块
            var splitBigFile = function(file, file_length, step) {
                var step_times = Math.ceil(file_length / step)
                var start = 0
                var block_arr = []

                for (i = 0; i < step_times; i++) {
                    var block = file.slice(start, start + step)
                    start = start + step
                    block_arr.push(block)
                }

                return block_arr
            }

            var handleBigFile = async function(big_files) {
                return Promise.all([].map.call(big_files, function(file, index) {
                    return new Promise(function(resolve, reject) {
                        // 先读取到 ArrayBuffer,再获取 ArrayBuffer 的 Uint8Array 字节数组形式,最后用 base64 编码字节数组用于传输。
                        var view = new Uint8Array(file)             // 提取二进制字节数组,使用 Uint8Array 表示
                        var base64_data = binary2base64(view)       // base64 编码

                        console.log("==== handle upload start ====");
                        console.log("block index = ", index);
                        console.log("data = ", base64_data);
                        console.log("==== handle upload end ====");
                        resolve("Promise file")
                    })
                })).then(function(results) {
                    return results;
                })
            }

            // 二进制字节数组转 base64 编码的字符串
            var binary2base64 = function(bi) {
                let str = '';
                for (let i = 0, len = bi.length; i < len; i++) {
                    str += String.fromCharCode(bi[i]);
                }
                return btoa(str);
            }

            var __main = function() {
                // 禁止浏览器的拖拽默认事件
                globalDragFile()

                // 识别指定区域的拖动效果
                localDragFile()
            }

            __main()
        })()
    </script>
</body>
</html>

到了这里,关于浏览器中处理上传大文件——FileReader.readAsArrayBuffer()方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JS-27 前端数据请求方式;HTTP协议的解析;JavaScript XHR、Fetch的数据请求与响应函数;前端文件上传XHR、Fetch;安装浏览器插件FeHelper

    早期的网页都是通过后端渲染来完成的,即服务器端渲染(SSR,server side render): 客户端发出请求 - 服务端接收请求并返回相应HTML文档 - 页面刷新,客户端加载新的HTML文档; 服务器端渲染的缺点: 当用户点击页面中的某个按钮向服务器发送请求时,页面本质上只是一些数

    2024年02月16日
    浏览(57)
  • oss/obs对象存储上传图片,在浏览器输入地址却是下载图片。不能直接在浏览器上查看。

    1.问题 oss/obs对象存储上传图片获取链接地址后,在浏览器输入地址却是下载。不能直接在浏览器上面浏览图片信息。 2.解决 上传文件的时候需要设置:content-type类型,需要指示浏览器这是什么类型,这样才能在浏览器上面浏览图片信息。浏览器是根据response-headerl里面的Con

    2024年02月15日
    浏览(37)
  • Selenium多浏览器处理

    Python 版本 Java 版本 启动的时候设置 browser 使用的浏览器驱动,就可以进行多浏览器的处理 Python 版本 Java 版本 在 Windows 下比较特殊,要使用 Windows 下的 set 来给变量赋值 Python 版本 Java 版本 需要注意的是,要先将各个浏览器的驱动配置好,具体的配置方式参考 Selenium 安装章

    2024年02月14日
    浏览(27)
  • Python + Selenium 处理浏览器Cookie

    工作中遇到这么一个场景:自动化测试登录的时候需要输入动态验证码,由于某些原因,需要从一个已登录的机器上,复制cookie过来,到自动化这边绕过登录。 浏览器的F12里复制出来的cookie内容是文本格式的: 这里需要把cookie文本处理为name和value格式的字典形式,这个是S

    2024年02月13日
    浏览(48)
  • 自动化测试——selenium多浏览器处理

    用户使用的浏览器(frefox,chrome,IE 等) web应用应该能在任何浏览器上正常的工作,这样能吸引更多的用户来使用。 是跨不同浏览器组合验证网站或web应用程序功能的过程 是 兼容性测试的一个分支,用于保持功能和质量的一致性 适用于面向客户的网站和组织内部使用的站点 py

    2024年02月11日
    浏览(49)
  • 浏览器刷新页面,缓存的处理方式,强制刷新

    刷新页面的缓存处理的方式对比 地址栏回车/直接访问 URL 保留强缓存,保留协商缓存,走正常请求流程 点击浏览器刷新按钮 忽略强缓存,保留协商缓存 按f5【command + r】 忽略强缓存,保留协商缓存 ctrl + f5 【command + shift + r 】 忽略强缓存,忽略协商缓存,从服务器端请求最

    2024年02月02日
    浏览(35)
  • 软件测试 | Selenium对多浏览器处理

    在执行自动化测试过程中,我们往往会针对不同的浏览器做兼容性测试,可以通过对测试用例代码的改造,实现对不同浏览器的自动化兼容性测试。 注:实现对不同浏览器的自动化兼容性测试,需要先将各个浏览器的驱动在PC端配置好,具体的配置方式可参考Selenium的官方文

    2024年02月12日
    浏览(40)
  • vue如何进行跨浏览器兼容性处理

    让我来和你聊一聊如何让你的Vue应用在不同的浏览器和操作系统上正常运行。 首先呢,我们要知道一个事实:不同的浏览器有不同的特点和偏好,就像每个人都有独特的个性和习惯一样。你想要让你的应用在每个人的浏览器上都正常运行,就要像交朋友一样,要尊重每个浏览

    2024年02月07日
    浏览(42)
  • 记一次浏览器下载错误处理-失败网络错误

    背景 最近在自己电脑上Chrome浏览器正常使用,但只要是下载软件,就会在下载几十秒后,自动停止,报 失败-网络错误 ,导致文件都下载不成功,如下图。 猜测是更改了哪块的配置,导致一直中断,可以依次检查以下几种方案。 1)检查下载文件目录是否存在 2)检查网络是

    2023年04月16日
    浏览(37)
  • 【浏览器篇】记录下浏览器保存PDF文件不同方式的小区别

    以前不太注意这些,最近搞文档比较多才发现为何保存的一部分PDF文件里面字体可以复制可以搜索,一部分保存的PDF里面的字体却无法复制、无法搜索等,发现是不同保存方式得到的文档权限不一样,做个记录!—【蘇小沐】 1.实验环境 系统 版本 Windows 11 专业工作站版 22H

    2024年02月12日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包