カメリアの記事

意味があることやないことを綴ります

JavaScript の FileReader() で複数のファイルを受け取る

UI から得たファイルを受け取るには FileReader() を使うらしいのですが、複数を処理するにはちょっとコツが必要なようです。

具体的には下のようなコードになります。

function getFiles(event) {
  let work = []
  let collection = event.dataTransfer.files
           // or = event.target.files
  let fr = new FileReader()
  return new Promise(resolve => {
    let i = 0
    fn()
    function fn() {
      fr.readAsText(collection[i])
      fr.onload = () => {
        work[i] = fr.result
        if (i < collection.length - 1) {
          i++
          fn()
        }
        else {
          resolve(work)
        }
      }
    }
  })
}

event から file collection を受け取る

まずは受け取ります。画面上にドロップされたファイルは evetn.dataTransfer.files で、ファイル選択画面から入力されたファイルは event.target.files で受け取ります。

FileReader()

FileReader() をセットします。データの取り出しは繰り返し処理で何度も行いますが、 FileReader() は 1 回だけ使います。

再帰処理

ファイルの数だけ繰り返し処理です。 for 文を使うと FileReader() のデータ吸いだしが同時に発生して怒られるので再帰処理をします。再帰処理の部分だけ抜き出すと下のようになります。

return new Promise(resolve => {
  let i = 0
  fn()
  function fn() {
    // 処理
    if (i < collection.length - 1) {
      i++
      fn()
    }
    else {
      resolve(work)
    }
  }
})

readAsText()

テキストファイルを受け取るには readAsText() を使います。受け取るファイルに応じて適宜変更が必要です。

onload

データを読むのに時間がかかるみたいです。 onload のイベントが発生するのでこれを待って処理を行います。

result

読み込みが終わったら result で結果を受け取ります。

終わりに

FileReader() を 1 回だけ作るのではなく fr[i] = new FileReader() などしていれば再帰処理ではなくfor 文が使えたのかもしれないな、と今さら思っています。どうなんでしょうね。