• home > webfront > SGML > web >

    前端JS超大文件读取:浏览器与nodejs如何做大文件操作

    Author:zhoulujun Date:

    浏览器的文件读取HTML5 的FileReader API 可以让客户端浏览器对用户本地文件进行读取,这样就不再需要上传文件由服务器进行读取了,这

    浏览器的文件读取

    HTML5 的FileReader API 可以让客户端浏览器对用户本地文件进行读取,这样就不再需要上传文件由服务器进行读取了,这大大减轻了服务器的负担,也节省了上传文件所需要的时间。不过在实践中我发现用FileReader.readAsText()可以轻易地处理一个 300k 的日志文件,但当日志文件有 1G、甚至 2G 那么大,浏览器就会崩溃。这是因为readAsText()会一下子把目标文件加载至内存,导致内存超出上限。所以如果 Web 应用常常需要处理大文件时,我们应该使用FileReader.readAsArrayBuffer()来一块一块读取文件。

    由于 JavaScript 中的File对象继承自Blob,所以我们完全可以用Blob.slice()方法将文件切成小块来处理,大致思路是:

    1. 先取文件的前 10k 内容,转换成文本

    2. 从头获取每一行的前 19 个字符,判断是否满足日期的格式,如果满足那么这 19 个字符就是开始时间

    3. 再取文件尾部的 10k 内容,转换成文本

    4. 同理从尾部内容遍历每一行来获取结束时间

    <input type="file" id="file" />
    <button id="get-time">Get Time</button>
    <script>
        document.getElementById('get-time').onclick = function () {
            let file = document.getElementById('file').files[0];
            let fr = new FileReader();
            let CHUNK_SIZE = 10 * 1024;
            let startTime, endTime;
            let reverse = false;
            fr.onload = function () {
                let buffer = new Uint8Array(fr.result);
                let timeReg = /\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2}/;
                for (
                    let i = reverse ? buffer.length - 1 : 0;
                    reverse ? i > -1 : i < buffer.length;
                    reverse ? i-- : i++
                ) {
                    if (buffer[i] === 10) {
                        let snippet = new TextDecoder('utf-8').decode(
                            buffer.slice(i + 1, i + 20)
                        );
                        if (timeReg.exec(snippet)) {
                            if (!reverse) {
                                startTime = snippet;
                                reverse = true;
                                seek();
                            } else {
                                endTime = snippet;
                                alert(`Log time range: ${startTime} ~ ${endTime}`);
                            }
                            break;
                        }
                    }
                }
            };
            seek();
            function seek() {
                let start = reverse ? file.size - CHUNK_SIZE : 0;
                let end = reverse ? file.size : CHUNK_SIZE;
                let slice = file.slice(start, end);
                fr.readAsArrayBuffer(slice);
            }
        };
    </script>


    Node读取超大文件

    nodejs读取文件有:

    • fs.readFile

    • fs.createReadStream() & readLine

    • fs.createReadStream() & event-stream

    第一个方法很明显不适用,如果你尝试把超大文件直接读入内存中!

    const fs = require('fs')
    const readFileTest = () => {
        var data = ''
        var rs = fs.createReadStream('./video.mp4');
        rs.on('data', function(chunk) {
            data += chunk;
         });
        rs.on('end',function(){
            console.log(data);
        });
        rs.on('error', function(err){
            console.log(err.stack);
         });
    }
    readFileTest()


    分片读取

     createReadStream在读取文件的过程中,其实也可以分段读取,这种分段读取的方法也可以做为大文件读取的备选项。特别是在并发读取的时候有一定的优点,可以提升文件读取和处理的速度。

    createReadStream接受第二个参数{start,end}。我们可以通过fs.promises.stat来获取文件的大小,然后确定分片,最后分片一次读取,比如:

    const readStremfunc = () => {
        const readStream =  fs.createReadStream(filepath,{start:start,end:end})
        readStream.setEncoding('binary')
        let data = ''
        readStream.on('data', chunk => {
            data = data + chunk
        })
        readStream.end('data', () => {
          ...
        })
    }





    参考文章:

    使用FileReader.readAsArrayBuffer()在浏览器中处理大文件 https://joji.me/zh-cn/blog/processing-huge-files-using-filereader-readasarraybuffer-in-web-browser/

    深入浅出Nodejs中的大文件读写 https://juejin.cn/post/7148051371060068389




    转载本站文章《前端JS超大文件读取:浏览器与nodejs如何做大文件操作》,
    请注明出处:https://www.zhoulujun.cn/html/webfront/SGML/web/2024_0808_9213.html