大文件上的filereader API

51

我的文件读取API代码一直运行得很好,直到有一天我从一个客户那里得到了一个280MB的txt文件。在Chrome中页面直接崩溃,在Firefox中什么也没有发生。

// create new reader object 
var fileReader = new FileReader(); 

// read the file as text 
fileReader.readAsText( $files[i] );  
fileReader.onload = function(e) 
{   // read all the information about the file 
    // do sanity checks here etc... 
    $timeout( function() 
    {    
        // var fileContent = e.target.result;
        // get the first line 
        var firstLine = e.target.result.slice(0, e.target.result.indexOf("\n") ); }}

我试图在上面做的是获取第一个换行符,以便我可以获取文件的列长度。我不应该把它读成文本吗?在大型文件中如何获取文件的列长度而不破坏页面?


我成功处理了在浏览器中逐行读取大文件的示例:https://dev59.com/W1kS5IYBdhLWcg3wxJAF#55377748 - Maz T
2个回答

95

由于在处理之前将整个文件读入内存,因此您的应用程序在处理大文件时失败。通过流式传输文件(读取小块),可以解决这种低效率问题,因此您只需要在内存中保存部分文件。

File对象也是Blob实例,提供了.slice方法来创建文件的较小视图。

下面是一个假定输入为ASCII的示例(演示:http://jsfiddle.net/mw99v8d4/)。

function findColumnLength(file, callback) {
    // 1 KB at a time, because we expect that the column will probably small.
    var CHUNK_SIZE = 1024;
    var offset = 0;
    var fr = new FileReader();
    fr.onload = function() {
        var view = new Uint8Array(fr.result);
        for (var i = 0; i < view.length; ++i) {
            if (view[i] === 10 || view[i] === 13) {
                // \n = 10 and \r = 13
                // column length = offset + position of \r or \n
                callback(offset + i);
                return;
            }
        }
        // \r or \n not found, continue seeking.
        offset += CHUNK_SIZE;
        seek();
    };
    fr.onerror = function() {
        // Cannot read file... Do something, e.g. assume column size = 0.
        callback(0);
    };
    seek();

    function seek() {
        if (offset >= file.size) {
            // No \r or \n found. The column size is equal to the full
            // file size
            callback(file.size);
            return;
        }
        var slice = file.slice(offset, offset + CHUNK_SIZE);
        fr.readAsArrayBuffer(slice);
    }
}

上面的代码片段计算换行符之前的字节数。如果要计算由多字节字符组成的文本中的字符数,则稍微困难一些,因为您必须考虑到块中的最后一个字节可能是多字节字符的一部分。


6
你现在是我的英雄。一开始,我试着把它分成小块来阅读,但是我不够了解,做不到。你不知道我有多么感激。谢谢! - ODelibalta
如果我需要确定文件中的最后一个块,你会推荐什么?我正在使用的系统有一个不同的REST API用于最后一个块,然后提交整个文件。但是我无法确定最后一块。如果您不介意查看我的问题,那将非常有帮助http://stackoverflow.com/questions/39312451/determining-the-last-file-chunk/39312577#39312577 - Batman
1
我在想如何使用这个来读取大文件中的n行..... :/ - gsamaras
1
关于多字节字符的困境,TextDecoder#decode现在/即将拥有一个stream选项标志,以解决这个问题。 - Blake Regalia
@RobW,我们如何逐块预览大图像?如果每个图像大小>25mb,总多个图像大小约为900mb以显示?我们如何在img src上设置分块视图? - Developer

5

有一个很棒的库叫做Papa Parse,可以以优雅的方式处理这个问题!它真正地处理大文件,而且你还可以使用Web Worker。

只需尝试他们提供的演示:https://www.papaparse.com/demo


2
CSV解析器?这有用吗? - yue you
2
这对于想要直接在浏览器中处理CSV文件而不是将其发送到后端的情况非常有帮助。 - Edy Segura
1
只是想强调一下@EdySegura所说的,PapaParse非常好用,能够提供更流畅的用户体验(因为始终是离线优先的)。 - gabriel.hayes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接