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.