Back

FileReader APIを使用したファイル操作

FileReader APIを使用したファイル操作

Webアプリでユーザーがファイルを選択すると、Fileオブジェクトが取得できますが、その内容を実際に読み取るにはどうすればよいでしょうか?そこで登場するのがJavaScriptのFileReader APIです。この記事では、FileReaderの動作原理、使用すべきタイミング、そして最新の代替手段との比較について解説します。

重要なポイント

  • FileReader APIは、readAsText()readAsArrayBuffer()readAsDataURL()の3つのメソッドのいずれかを使用して、FileまたはBlobの内容を非同期で読み取ります。
  • FileReaderは、loaderrorprogressなどのイベントを使用して結果を通知するイベント駆動型モデルを採用しています。
  • FileReaderをPromiseでラップすることで、async/awaitコードとのよりクリーンな統合が可能になります。
  • 最新のBlob.text()Blob.arrayBuffer()メソッドは基本的な読み取りにはよりシンプルですが、進捗状況の追跡、UTF-8以外のエンコーディング、base64データURLが必要な場合は、FileReaderが依然として適切な選択肢です。

FileReader APIとは?

FileReader APIは、FileまたはBlobオブジェクトの内容を非同期で読み取るブラウザインターフェースです。パスを指定してユーザーのシステム上の任意のファイルにアクセスすることはできません。<input type="file">またはドラッグ&ドロップ操作を通じてユーザーが明示的に選択したファイルのみを扱います。

const input = document.querySelector('input[type="file"]')

input.addEventListener('change', () => {
  const file = input.files[0]
  console.log(file.name, file.size, file.type)
})

FileオブジェクトはBlobを継承しているため、同じプロパティに加えてnamelastModifiedを持ちます。これをFileReaderの読み取りメソッドに直接渡すことができます。

3つの主要な読み取りメソッド

FileReaderを使用してJavaScriptでローカルファイルを読み取る際は、適切な出力形式を選択する必要があります:

  • readAsText(file, encoding?) — ファイルの内容を文字列として返します。デフォルトはUTF-8です。CSV、JSON、プレーンテキスト、またはあらゆるテキストベースの形式に有用です。
  • readAsArrayBuffer(file) — 生のバイナリデータをArrayBufferとして返します。画像、音声、PDF、またはあらゆるバイナリ処理に使用します。
  • readAsDataURL(file) — base64エンコードされたdata: URLを返します。画像プレビューに便利ですが、base64エンコーディングのオーバーヘッドにより、結果は元のファイルより約33%大きくなることに注意してください。

readAsBinaryString()は避けてください — 非推奨です。バイナリデータには代わりにreadAsArrayBuffer()を使用してください。

FileReaderのイベント駆動型モデル

FileReaderは非同期で、イベントを通じて通信します。主要なイベントは以下の通りです:

イベント発火タイミング
loadstart読み取り開始時
progress読み取り中に定期的に発火
load読み取りが正常に完了
error読み取りが失敗
loadend読み取り終了(成功または失敗)

以下は、readAsDataURL()を使用したアップロード前の画像プレビューの実用的な例です:

function previewImage(file) {
  const reader = new FileReader()

  reader.addEventListener('load', () => {
    const img = document.querySelector('#preview')
    img.src = reader.result
  })

  reader.addEventListener('error', () => {
    console.error('Failed to read file:', reader.error)
  })

  reader.readAsDataURL(file)
}

progressイベントは、大きなファイルでプログレスバーを表示する際に特に有用です:

reader.addEventListener('progress', (event) => {
  if (event.lengthComputable) {
    const percent = Math.round((event.loaded / event.total) * 100)
    progressBar.value = percent
  }
})

FileReaderをPromiseでラップする

FileReaderのコールバックスタイルは、最新の非同期コードでは扱いにくく感じることがあります。シンプルなラッパーでこれを解決できます:

function readFileAsText(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.addEventListener('load', () => resolve(reader.result))
    reader.addEventListener('error', () => reject(reader.error))
    reader.readAsText(file)
  })
}

// 使用例
const text = await readFileAsText(file)

FileReader vs Blob.text()とBlob.arrayBuffer()

最新のブラウザは、Blob(したがってFile)上で直接Promiseベースのメソッドをサポートしています:

// 最新のアプローチ — 基本的な読み取りにはよりシンプル
const text = await file.text()
const buffer = await file.arrayBuffer()

では、いつFileReaderを使用すべきでしょうか?以下の場合に選択してください:

  • 進捗状況の追跡progressイベント経由で必要な場合(ただし、ローカルファイルの場合、一部のブラウザでは少数のprogressイベントしか発火しない可能性があります)
  • UTF-8以外のエンコーディングのサポートがreadAsText(file, 'ISO-8859-1')経由で必要な場合
  • Base64データURLreadAsDataURL()経由で必要な場合
  • より広範なレガシーブラウザサポートが必要な場合

最新のアプリで単純なテキストまたはバイナリ読み取りを行う場合、Blob.text()Blob.arrayBuffer()の方がクリーンです。画像プレビューの場合、URL.createObjectURL(file)はbase64の膨張を回避し、一般的にreadAsDataURL()よりもメモリ効率が良好です。ただし、メモリリークを避けるため、オブジェクトURLが不要になったらURL.revokeObjectURL()を呼び出すことを忘れないでください。

まとめ

FileReader APIは、ブラウザでFileオブジェクトを扱う際の実用的なツールであり続けています。特に進捗イベント、エンコーディング制御、データURLが必要な場合に有用です。よりシンプルなケースでは、新しいBlobメソッドの方が少ないコードで済みます。両方を理解しておけば、あらゆるファイル読み取りシナリオをクリーンに処理できます。

よくある質問

いいえ。FileReaderは、input要素またはドラッグ&ドロップ操作を通じてユーザーが明示的に選択したファイルのみを読み取ることができます。ブラウザのセキュリティモデルは、JavaScriptがパスを指定してファイルシステム上の任意のファイルにアクセスすることを防ぎます。この制限は、ユーザーのプライバシーとシステムセキュリティを保護するために存在します。

readAsArrayBufferは、画像メタデータや音声波形の解析など、処理や操作に適した生のバイナリデータを返します。readAsDataURLは、画像のsrcやCSSの背景として直接使用できるbase64エンコードされた文字列を返します。データURLアプローチは便利ですが、元のファイルより約33パーセント大きい出力を生成します。

単にテキストコンテンツが必要で、アプリが最新のブラウザをターゲットにしている場合、Blob.text()は直接Promiseを返すためよりシンプルです。大きなファイルの進捗状況追跡が必要な場合、UTF-8以外のエンコーディングを指定する必要がある場合、またはBlob.text()メソッドを持たない古いブラウザをサポートする必要がある場合は、FileReaderを使用してください。

URL.createObjectURLを使用してプレビューURLを生成する場合、画像が読み込まれた後、またはプレビューが削除されたらURL.revokeObjectURLを呼び出してください。代わりにreadAsDataURLを使用する場合、base64文字列は自動的にガベージコレクションによって管理されますが、同じファイルに対してオブジェクトURLよりも多くのメモリを消費します。

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay