stack overflowのコードをアレンジして実現。
chunk_size
ずつファイルを読み込み、読み込んだファイルを一文字ずつ変数に追加、改行を見つけたら callback
を適用して変数のメモリを解放する。なお、全ての改行コードに対応しているが、出力時には \n に統一される。
残念ながら改行のないテキストデータには使えない。javascriptの変数に格納できる文字数の最大値(Chromeであれば268,435,440文字)を超えた時点でエラーが起きる(その前にタブが落ちる可能性もあるが)。
readBigTextForEachLine = (file, callback, chunk_size = 1024) => {
let offset = 0;
let text = "";
let slice = "";
let fr = new FileReader();
fr.onload = (event) => {
if(typeof fr.result === "string") {
callback(text + fr.result.replace(/\r/g, "\n"));
return true;
}
let view = new Uint8Array(fr.result);
for(let i=0, l=view.length; i<l; i++) {
if(view[i] === 13) { // \n = 10 and \r = 13
if(view[i+1] === 10) {
i++;
}
callback(text + "\n");
text = "";
continue;
}
text += String.fromCharCode(view[i]);
}
seek();
};
fr.onerror = () => {
callback("Failed to read file.");
};
let seek = () => {
if (offset + chunk_size >= file.size) {
slice = file.slice(offset);
fr.readAsText(slice);
} else {
slice = file.slice(offset, offset + chunk_size);
fr.readAsArrayBuffer(slice);
}
offset += chunk_size;
}
seek();
}
使い方の例は以下。第二引数にconsole.log
を指定しているので、改行を見つけるたびにコンソールに内容が出力される。
<script>
document.getElementById("upload").onchange = (e) => {
let file = e.target.files[0];
readBigTextForEachLine(file, console.log);
};
</script>
<html><body>
Upload Big File: <input type="file" id="upload">
</body></html>