元々は Blob
や File
の内容を読み込むのに FileReader
が必要でしたが、最新版の JavaScript では不要です。
参考「FileReader - Web APIs | MDN」
参考「Blob - Web APIs | MDN」
参考「File - Web APIs | MDN」
1. 読み込み
1.1. テキスト
1.1.1. UTF-8
const blob = new Blob(['foo\n'], { type: 'text/plain' });
const text = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = () => reject(reader.error);
reader.onload = () => resolve(reader.result);
reader.readAsText(blob);
});
console.log(text);
const blob = new Blob(['foo\n'], { type: 'text/plain' });
const text = await blob.text();
console.log(text);
1.1.2. UTF-8 以外
const blob = new Blob(['foo\n'], { type: 'text/plain' });
const text = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = () => reject(reader.error);
reader.onload = () => resolve(reader.result);
reader.readAsText(blob, 'shift-jis');
});
console.log(text);
const blob = new Blob(['foo\n'], { type: 'text/plain' });
const arrayBuffer = await blob.arrayBuffer();
const textDecoder = new TextDecoder('shift-jis');
console.log(textDecoder.decode(arrayBuffer));
1.2. ArrayBuffer
const blob = new Blob(['foo\n'], { type: 'text/plain' });
const arrayBuffer = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = () => reject(reader.error);
reader.onload = () => resolve(reader.result);
reader.readAsArrayBuffer(blob);
});
const textDecoder = new TextDecoder();
console.log(textDecoder.decode(arrayBuffer));
const blob = new Blob(['foo\n'], { type: 'text/plain' });
const arrayBuffer = await blob.arrayBuffer();
const textDecoder = new TextDecoder();
console.log(textDecoder.decode(arrayBuffer));
1.3. URL
FileReader
を用いることでデータ URL を得られますが、データ URL を使用することによって様々な問題が発生する可能性があります。
特に理由がなければオブジェクト URL を使用する方が安全です。
const blob = new Blob(['foo\n'], { type: 'text/plain' });
const url = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = () => reject(reader.error);
reader.onload = () => resolve(reader.result);
reader.readAsDataURL(blob);
});
console.log(url);
const blob = new Blob(['foo\n'], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
console.log(url);
URL.revokeObjectURL(url);
パーセントエンコードまたは Base64 エンコードを用いてデータ URL を生成することも可能です。
const blob = new Blob(['foo\n'], { type: 'text/plain' });
const text = await blob.text();
const url = 'data:text/plain,' + encodeURIComponent(text);
console.log(url);
const blob = new Blob(['foo\n'], { type: 'text/plain' });
const arrayBuffer = await blob.arrayBuffer();
const uint8Array = new Uint8Array(arrayBuffer);
const binaryString = uint8Array.reduce(
(binaryString, uint8) => binaryString + String.fromCharCode(uint8),
'',
);
const url = 'data:text/plain;base64,' + btoa(binaryString);
console.log(url);
参考「データ URL - URI | MDN」
参考「URL: createObjectURL() 静的メソッド - Web API | MDN」
参考「Base64 - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN」
参考「[JavaScript] Unicode 文字列やバイナリデータを Base64 エンコードおよびデコードする - Qiita」
2. 読み込み中
ReadableStream
を使用することで読み込み中の処理を行えます。
const blob = new Blob(['foo\n'], { type: 'text/plain' });
const text = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = () => reject(reader.error);
reader.onload = () => resolve(reader.result);
reader.onprogress = event => {
if ( event.lengthComputable ) {
// 進捗状況
console.log('%d / %d', event.loaded, event.total);
}
};
reader.readAsText(blob);
});
console.log(text);
const blob = new Blob(['foo\n'], { type: 'text/plain' });
const readableStream = new ReadableStream({
loaded: 0,
total: blob.size,
async start(controller) {
const readableStream = await blob.stream();
for await (const chunk of readableStream) {
controller.enqueue(chunk);
// 進捗状況
this.loaded += chunk.length;
console.log('%d / %d', this.loaded, this.total);
}
controller.close();
},
});
const text = await new Response(readableStream).text();
console.log(text);
const blob = new Blob(['foo\n'], { type: 'text/plain' });
const readableStream = new ReadableStream({
loaded: 0,
total: blob.size,
intervalID: 0,
progress() {
// 進捗状況
console.log('%d / %d', this.loaded, this.total);
},
async start(controller) {
// 進捗状況
this.intervalID = setInterval(() => this.progress(), 50);
//
const readableStream = await blob.stream();
for await (const chunk of readableStream) {
controller.enqueue(chunk);
// 進捗状況
this.loaded += chunk.length;
}
controller.close();
// 進捗状況
clearInterval(this.intervalID);
this.progress();
},
cancel() {
// 進捗状況
clearInterval(this.intervalID);
},
});
const text = await new Response(readableStream).text();
console.log(text);
※ FileReader
の progress イベントは約 50ms ごとに発生します。
参考「ReadableStream - Web API | MDN」
参考「6.2. The FileReader API - File API」(「約 50ms」)
3. 読み込み中止
ReadableStream
を使用することで読み込みを中止出来ます。
const blob = new Blob(['foo\n'], { type: 'text/plain' });
const text = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onabort = () => resolve();
reader.onerror = () => reject(reader.error);
reader.onload = () => resolve(reader.result);
reader.readAsText(blob);
// 中止
reader.abort();
});
const blob = new Blob(['foo\n'], { type: 'text/plain' });
const readableStream = await blob.stream();
// 中止
await readableStream.cancel();
参考「ReadableStream - Web API | MDN」。
4. 関連記事
参考「イマドキな JavaScript で書かない・使わないもの: var, function, then, jQuery, その他 - Qiita」