序章

サポートするWebブラウザ FileReaderユーザーがファイルをアップロードできるようにします。

この記事では、FileFileReader、およびFileReaderSyncAPIについて説明します。

前提条件

この記事をフォローしたい場合は、次のものが必要になります。

  • JavaScriptのメソッド EventListener 、およびPromisesを理解しておくと役立ちます。
  • コードエディタ。
  • FileFileReader、およびFileReaderSyncをサポートする最新のWebブラウザー。

ファイルのアップロード

まず、ユーザーからファイルを取得するには、<input>要素を使用する必要があります。

<input id="input" type="file" />

このコードにより、ユーザーは自分のマシンからファイルをアップロードできます。

HTML<form>を使用してファイルをアップロードする例を次に示します。

<form enctype="multipart/form-data" action="/upload" method="post">
  <input id="input" type="file" />
</form>

アップロードの処理をより細かく制御するために、HTML<form>の代わりにJavaScriptを使用してファイルを送信できます。

let file = document.getElementById('input').files[0];
let formData = new FormData();

formData.append('file', file);
fetch('/upload/image', {method: "POST", body: formData});

このアプローチでは、FormDataおよびfetchを使用します。

FileBlobプロパティの使用

最近のブラウザでは、FilesにはBlobのプロパティと機能があります。 これらの関数を使用すると、ファイルを読み取ることができます。

  • .text()は、ファイルをストリームに変換してから文字列に変換します。
  • .stream()ReadableStreamを返します。
  • .arrayBuffer()は、blobのデータをバイナリ形式で含むArrayBufferを返します。
  • .slice()を使用すると、ファイルのスライスを取得できます。

テキストを含む新しいmyFile.txtファイルを作成します。

myFile.txt
Example file content.

次に、新しいfile-blob-example.htmlファイルを作成します。

file-blob-example.html
<!DOCTYPE html>
<html>
<body>
  <input type="file" id="input" />

  <script>
    const streamToText = async (blob) => {
      const readableStream = await blob.getReader();
      const chunk = await readableStream.read();

      return new TextDecoder('utf-8').decode(chunk.value);
    };

    const bufferToText = (buffer) => {
      const bufferByteLength = buffer.byteLength;
      const bufferUint8Array = new Uint8Array(buffer, 0, bufferByteLength);

      return new TextDecoder().decode(bufferUint8Array);
    };

    document.getElementById('input').addEventListener('change', function(e) {
      let file = document.getElementById('input').files[0];

      (async () => {
        const fileContent = await file.text();

        console.log('.text()', fileContent);

        const fileContentStream = await file.stream();

        console.log('.stream()', await streamToText(fileContentStream));

        const buffer = await file.arrayBuffer();

        console.log('.buffer()', bufferToText(buffer));

        const fileSliceBlob = file.slice(0, file.length);
        const fileSliceBlobStream = await fileSliceBlob.stream();

        console.log('.slice() and .stream()', await streamToText(fileSliceBlobStream));
      })();
    });
  </script>
</body>
</html>

Webブラウザでfile-blob-example.htmlを開き、myFile.txtファイルをinputに追加します。 Web開発者コンソールで、.text().stream().buffer()、および.slice()を使用して読み取られたファイルの内容が表示されます。

このアプローチでは、 ReadableStream TextDecoder()、および Uint8Array()を使用します。

FileReaderのライフサイクルと方法の適用

FileReaderには6つの主要なイベントが添付されています。

  • loadstart:ファイルのロードを開始すると発生します。
  • progress:blobがメモリに読み込まれたときに発生します。
  • abort.abortを呼び出すと発生します。
  • error:エラーが発生したときに発生します。
  • load:読み取りが成功したときに発生します。
  • loadend:ファイルがロードされ、エラーまたはアボートが呼び出されなかった場合、またはロードが新しい読み取りを開始した場合に発生します。

ファイルのロードを開始するには、次の4つの方法があります。

  • readAsArrayBuffer(file):ファイルまたはBLOBを配列バッファーとして読み取ります。 1つのユースケースは、大きなファイルをServiceWorkerに送信することです。
  • readAsBinaryString(file):ファイルをバイナリ文字列として読み取ります
  • readAsText(file, format):ファイルをUSVString(ほとんど文字列のように)として読み取り、オプションの形式を指定できます。
  • readAsDataURL(file):これにより、ファイルのコンテンツにアクセスできるURLが返されます。このURLは、Base64でエンコードされており、サーバーに送信する準備ができています。

readAsDataURL()を使用する新しいfilereader-example.htmlファイルを作成します。

filereader-example.html
<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      background: #000;
      color: white;
    }

    #progress-bar {
      margin-top: 1em;
      width: 100vw;
      height: 1em;
      background: red;
      transition: 0.3s;
    }
  </style>
</head>
<body>
  <input type="file" id="input" />
  <progress value="0" max="100" id="progress-bar"></progress>
  <div id="status"></div>
  <script>
    const changeStatus = (status) => {
      document.getElementById('status').innerHTML = status;
    }

    const setProgress = (e) => {
      const fr = e.target;
      const loadingPercentage = 100 * e.loaded / e.total;

      document.getElementById('progress-bar').value = loadingPercentage;
    }

    const loaded = (e) => {
      const fr = e.target;
      var result = fr.result;

      changeStatus('Finished Loading!');
      console.log('Result:', result);
    }

    const errorHandler = (e) => {
      changeStatus('Error: ' + e.target.error.name);
    }

    const processFile = (file) => {
      const fr = new FileReader();

      fr.readAsDataURL(file);
      fr.addEventListener('loadstart', changeStatus('Start Loading'));
      fr.addEventListener('load', changeStatus('Loaded'));
      fr.addEventListener('loadend', loaded);
      fr.addEventListener('progress', setProgress);
      fr.addEventListener('error', errorHandler);
      fr.addEventListener('abort', changeStatus('Interrupted'));
    }

    document.getElementById('input').addEventListener('change', (e) => {
      const file = document.getElementById('input').files[0];

      if (file) {
        processFile(file);
      }
    });
  </script>
</body>
</html>

Webブラウザでfilereader-example.htmlを開き、myFile.txtファイルをinputに追加します。 ファイルが処理されると、プログレスバーが画面に表示されます。 正常に読み込まれると、'Start Loading''Loaded'、および'Finished Loading'と表示されます。

FileReaderSyncを使用する

FileReaderは、ファイルの読み取り中にメインスレッドをブロックしたくないため、非同期APIです。 たとえば、ブラウザが非常に大きなファイルを読み取ろうとしているときに、ユーザーインターフェイスが機能しなくなることは望ましくありません。 ただし、FileReaderSyncと呼ばれるFileReaderの同期バージョンがあります。 FileReaderSyncはWebワーカーでのみ使用できます。 Webワーカーには独自のスレッドがあるため、メインスレッドをブロックすることはありません。 FileReaderSyncFileReaderと同じ方法を使用します。

  • FileReaderSync.readAsArrayBuffer()
  • FileReaderSync.readAsBinaryString()
  • FileReaderSync.readAsText()
  • FileReaderSync.readAsDataURL()

同期しているため、イベントハンドラーはありません。

結論

この記事では、FileFileReader、およびFileReaderSyncAPIについて説明しました。

時間をかけてこれらの機能のブラウザサポートをチェックし、プロジェクトのユーザーに適用できることを確認してください。

追加のWebAPIで学習を続けてください。