Линии нет большого текстового файла

самый маленький файл у меня есть > 850k строк, и каждая строка имеет неизвестную длину. Цель состоит в том, чтобы прочитать n строки из этого файла в браузере. Полного прочтения не произойдет.

вот HTML <input type="file" name="file" id="file"> и JS у меня есть:

var n = 10;
var reader = new FileReader();
reader.onload = function(progressEvent) {
  // Entire file
  console.log(this.result);

  // By lines
  var lines = this.result.split('n');
  for (var line = 0; line < n; line++) {
    console.log(lines[line]);
  }
};

очевидно, проблема здесь в том, что он пытается сначала реализовать весь файл, а затем разделить его на новую строку. Так что не важно n, это попробовать чтобы прочитать весь файл и в конечном итоге прочитать ничего, когда файл большой.

как я должен это сделать?

примечание: Я готов удалить всю функцию и начать с нуля, учитывая, что я буду в состоянии console.log() каждая строка, которую мы читаем.


* "каждая строка имеет неизвестную длину" - > означает, что файл выглядит примерно так:

(0, (1, 2))
(1, (4, 5, 6))
(2, (7))
(3, (8))

Edit:

путь будет чем-то вроде api filereader для больших файлов, но я не вижу, как Я могу изменить это, чтобы прочитать n строки файла...

С помощью Uint8Array для строки в Javascript тоже оттуда можно сделать:

var view = new Uint8Array(fr.result);
var string = new TextDecoder("utf-8").decode(view);
console.log("Chunk " + string);

но это может не читать последнюю строку в целом, так как вы собираетесь определить строки позже? Например вот что он напечатал:

((7202), (u'11330875493', u'2554375661'))
((1667), (u'9079074735', u'6883914476',

2 ответов


логика очень похожа на то, что я написал в моем ответе api filereader для больших файлов, за исключением того, что вам нужно отслеживать количество строк, которые вы обработали до сих пор (а также последнюю строку, прочитанную до сих пор, потому что она, возможно, еще не закончилась). Следующий пример работает для любой кодировки, совместимой с UTF-8; Если вам нужна другая кодировка, посмотрите на опции для TextDecoder конструктор.

если вы уверены, что вход ASCII (или любая другая однобайтовая кодировка), то вы также можете пропустить использование TextDecoder и сразу прочитайте входной сигнал как текст используя FileReader ' s readAsText метод.

// This is just an example of the function below.
document.getElementById('start').onclick = function() {
    var file = document.getElementById('infile').files[0];
    if (!file) {
        console.log('No file selected.');
        return;
    }
    var maxlines = parseInt(document.getElementById('maxlines').value, 10);
    var lineno = 1;
    // readSomeLines is defined below.
    readSomeLines(file, maxlines, function(line) {
        console.log("Line: " + (lineno++) + line);
    }, function onComplete() {
        console.log('Read all lines');
    });
};

/**
 * Read up to and including |maxlines| lines from |file|.
 *
 * @param {Blob} file - The file to be read.
 * @param {integer} maxlines - The maximum number of lines to read.
 * @param {function(string)} forEachLine - Called for each line.
 * @param {function(error)} onComplete - Called when the end of the file
 *     is reached or when |maxlines| lines have been read.
 */
function readSomeLines(file, maxlines, forEachLine, onComplete) {
    var CHUNK_SIZE = 50000; // 50kb, arbitrarily chosen.
    var decoder = new TextDecoder();
    var offset = 0;
    var linecount = 0;
    var linenumber = 0;
    var results = '';
    var fr = new FileReader();
    fr.onload = function() {
        // Use stream:true in case we cut the file
        // in the middle of a multi-byte character
        results += decoder.decode(fr.result, {stream: true});
        var lines = results.split('\n');
        results = lines.pop(); // In case the line did not end yet.
        linecount += lines.length;
    
        if (linecount > maxlines) {
            // Read too many lines? Truncate the results.
            lines.length -= linecount - maxlines;
            linecount = maxlines;
        }
    
        for (var i = 0; i < lines.length; ++i) {
            forEachLine(lines[i] + '\n');
        }
        offset += CHUNK_SIZE;
        seek();
    };
    fr.onerror = function() {
        onComplete(fr.error);
    };
    seek();
    
    function seek() {
        if (linecount === maxlines) {
            // We found enough lines.
            onComplete(); // Done.
            return;
        }
        if (offset !== 0 && offset >= file.size) {
            // We did not find all lines, but there are no more lines.
            forEachLine(results); // This is from lines.pop(), before.
            onComplete(); // Done
            return;
        }
        var slice = file.slice(offset, offset + CHUNK_SIZE);
        fr.readAsArrayBuffer(slice);
    }
}
Read <input type="number" id="maxlines"> lines from
<input type="file" id="infile">.
<input type="button" id="start" value="Print lines to console">

потоки функцию!
Команда whatwg разрабатывает последний поток о записываемых + читаемых потоках и скоро будет готова. Но до тех пор есть web-stream-polyfill что вы можете использовать. Они работают над тем, чтобы получить ReadableStream от blob'S, а также [1]. Но я также создал способ получить blob в потоковой моде уже с: Винт-FileReader

вчера я также создал simpel порт of node-byline для работы с веб-потоков, а не

Так что это может быть довольно просто:

// Simulate a file
var csv =
`apple,1,.00
banana,4,.20
orange,3,.79`

var file = new Blob([csv])

var n = 0
var controller
var decoder = new TextDecoder
var stdout = new WritableStream({
  start(c) {
      controller = c
    },
    write(chunk, a) {
      // Calling controller.error will also put the byLine in an errored state
      // Causing the file stream to stop reading more data also
      if (n == 1) controller.error("don't need more lines")
      chunk = decoder.decode(chunk)
      console.log(`chunk[${n++}]: ${chunk}`)
    }
})

file
  .stream()
  .pipeThrough(byLine())
  // .pipeThrough(new TextDecoder) something like this will work eventually
  .pipeTo(stdout)
<script src="https://cdn.rawgit.com/creatorrr/web-streams-polyfill/master/dist/polyfill.min.js"></script>
<script src="https://cdn.rawgit.com/jimmywarting/Screw-FileReader/master/index.js"></script>

<!-- after a year or so you only need byLine -->
<script src="https://cdn.rawgit.com/jimmywarting/web-byline/master/index.js"></script>