简体   繁体   中英

How to read first line of a file in JavaScript

In JavaSctipt the FileReader object doesn't seem to have support for just reading the first line of a file. (up to the CR '\\n'). I dont want to read in the whole file to save memory.

Is there a way to do it?

My code (note that readLine() function does not exists):

    self.loadFirstLineFromFile = function (options, callback) {
        var hiddenElement = document.createElement('input');
        hiddenElement.id = 'hidden-tsv-file-loader';
        hiddenElement.type = 'file';
        hiddenElement.accept = options.extension;
        hiddenElement.style.display = 'none';
        hiddenElement.addEventListener('change', function (event) {
            var file = event.target.files[0];
            var reader = new FileReader(file);
            var firstLine;
            firstLine = reader.readLine();
            callback(firstLine);
        });
        document.body.appendChild(hiddenElement);
        hiddenElement.click();
    };

There's nothing builtin for that, but it's simple to implement:

var file = event.target.files[0];
var sliced = file.slice(0, 2048); // Pick a size that you're ok with
// NOTE: `await` keyword requires transpiling (Babel) for IE11,
// and to be inside an async function. An alternative is:
// sliced.text().then(function(text) { console.log(text); });
var text = await sliced.text();
console.log(text);

Here's an interface that reads the data from the Blob decoded as text and chunked by a delimiter :

async function* readLines (blob, encoding = 'utf-8', delimiter = /\r?\n/g) {
  const reader = blob.stream().getReader();
  const decoder = new TextDecoder(encoding);

  try {
    let text = '';

    while (true) {
      const { value, done } = await reader.read();

      if (done) break;

      text += decoder.decode(value, { stream: true });

      const lines = text.split(delimiter);

      text = lines.pop();
      yield* lines;
    }

    yield text;
  } finally {
    reader.cancel();
  }
}

We can use this to read a single line and discard the rest without reading the entire file:

hiddenElement.addEventListener('change', async function (event) {
  const file = event.target.files[0];

  for await (const line of readLines(file, 'utf-8', '\n')) {
    callback(line);
    return; // signals reader.cancel() to the async iterator
  }
});

Since I use Javascript with Knockout I refactored Patricks solution into this:

 self.loadStream = function (options, callback) {
        var hiddenElement = document.createElement('input');
        hiddenElement.id = 'hidden-tsv-file-loader';
        hiddenElement.type = 'file';
        hiddenElement.accept = options.extension;
        hiddenElement.style.display = 'none';
        hiddenElement.addEventListener('change', function (event) {
            var file = event.target.files[0];
            var reader = file.stream().getReader();
            var decoder = new TextDecoder('utf-8');
            var data;

            var readNextChunk = function () {
                data = reader.read();
                data.then(function (result) {
                    if (!result.value) {
                        callback({ chunk: '', done: true, shouldStop: true }, file);
                    } else {
                        var chunk = decoder.decode(result.value, { stream: true });
                        var args = {
                            chunk: chunk,
                            done: result.done,
                            shouldStop: true
                        };
                        callback(args, file);
                        if (!result.done && !args.shouldStop) {
                            readNextChunk();
                        }
                    }
                });
            };

            readNextChunk();
            hiddenElement.remove();
        });
        document.body.appendChild(hiddenElement);
        hiddenElement.click();
    };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM