[JS TS] Async / Await を使った File, Blob, ArrayBuffer, Base64 の相互変換関数の紹介
投稿日: 2024/07/26
ファイル操作をしているとFile, Blob, ArrayBuffer, Base64等の型に出会ってそれらを相互変換する機会はそれなりにあると思います。
それぞれ私が使っているコードを紹介するのでご活用ください。
JS標準で非同期関数が提供されてる機能については Async / Await で扱いやすくしたものを載せています。
番外編としてURL.createObjectURLについても少し書いてます。
相互変換できれば検証やテストの時にも便利です。
信頼性の加点になる情報としては、例えばfileToArrayBuffer
関数、fileToBase64
関数、objectURLToBlob
は ImgRoller のプロダクトのソースコードで実用しているコードです。パンダと戦うImgRollerをどうぞよろしく。
その他の関数も一応検証してます。
コードはTypeScriptで書いてますが、型を消せばJavascriptでも動くと思います。
FileまたはBlobからの変換
FileとBlobは扱いが近いので、まとめて扱えることが多いです。
FileまたはBlobからArrayBufferへの変換
readAsArrayBufferを使うと変換できますが、Async / Await が使われていないので扱いずらいです。そう思った人のためにAsync / Await で非同期処理をしたコードを紹介します。
export const fileToArrayBuffer = async ( file: File | Blob, ): Promise<ArrayBuffer> => { return new Promise((resolve, reject) => { const reader = new FileReader() reader.onload = () => { if (reader.result instanceof ArrayBuffer) { resolve(reader.result) } else { reject(new Error("FileReader result is not an ArrayBuffer")) } } reader.onerror = () => { reject(reader.error) } reader.readAsArrayBuffer(file) }) }
FileまたはBlobからBase64への変換
readAsDataURLをAsync / Await を用いて扱いやすく変えています。
ポイントとしてはreader.resultはreadAsDataURLを使ってる時点でstring型になるはずですが、型推論的にはArrayBuffer型とNull型も取ります。なので、ArrayBuffer型とNull型を除外しています。as any
で型エラーをつぶしてもいいのですが、こちらの方がきれいかなと思います。
export const fileToBase64 = async (file: File | Blob): Promise<string> => { return new Promise((resolve, reject) => { const reader = new FileReader() reader.onload = (e) => { if (reader.result instanceof ArrayBuffer || reader.result == null) { reject(new Error("FileReader result is not an string")) } else { resolve(reader.result) } } reader.onerror = (e) => { reject(e) } reader.readAsDataURL(file) }) }
Fileからの変換
FileからBlobへの変換
説明することありませんね。
mdnに従って変換するだけです。
export const fileToBlob = (file: File, mimeType: string) => { return new Blob([file], { type: mimeType }) }
Blobからの変換
BlobからのFileへの変換
こちらも説明することありませんね。
mdnに従って変換するだけです。
export const blobToFile = (blob: Blob, filename: string, mimeType: string) => { return new File([blob], filename, { type: mimeType }) }
ArrayBufferからの変換
ArrayBufferからFileへの変換
mdnに従って変換するだけです。
export const arrayBufferToFile = ( arrayBuffer: ArrayBuffer, filename: string, mimeType: string, ) => { return new File([arrayBuffer], filename, { type: mimeType }) }
ArrayBufferからBlobへの変換
mdnに従って変換するだけです。
export const arrayBufferToBlob = ( arrayBuffer: ArrayBuffer, mimeType: string, ) => { return new Blob([arrayBuffer], { type: mimeType }) }
ArrayBufferからbase64への変換
経験上、ArrayBufferからbase64への変換を行う機会はあまりないでしょう。したがって、新たに関数を作るよりは他で紹介した関数を用いて変換するのが良いでしょう。Blobを一度経由します。
export const arrayBufferToBase64 = async ( arrayBuffer: ArrayBuffer, mimeType: string, ) => { return await fileToBase64(arrayBufferToBlob(arrayBuffer, mimeType)) }
base64からの変換
base64からFileへの変換
export const base64ToFile = ( base64: string, filename: string, mimeType: string, ) => { const byteCharacters = atob(base64.split(",")[1]) const byteNumbers = Array.from(byteCharacters, (char) => char.charCodeAt(0)) const byteArray = new Uint8Array(byteNumbers) return new File([byteArray], filename, { type: mimeType }) }
base64からBlobへの変換
export const base64ToBlob = (base64: string, mimeType: string): Blob => { const byteCharacters = atob(base64.split(",")[1]) const byteNumbers = Array.from(byteCharacters, (char) => char.charCodeAt(0)) const byteArray = new Uint8Array(byteNumbers) return new Blob([byteArray], { type: mimeType }) }
base64からArrayBufferへの変換
経験上、base64からArrayBufferへの変換を行う機会はあまりないでしょう。したがって、新たに関数を作るよりは他で紹介した関数を用いて変換するのが良いでしょう。Blobを一度経由します。
export const base64ToArrayBuffer = (base64: string, mimeType: string) => { return fileToArrayBuffer(base64ToBlob(base64, mimeType)) }
番外編: URL.createObjectURLで作成したURLを相互変換
画像をこねるサービスを作っているとURL.createObjectURLも使うかもしれません。
これはブラウザが閉じたり、故意に開放するまでメモリ上にファイルを保持する機能です。
ブラウザ上に画像を表示するときなどに使います。
FileやBlobからObjectURLを作成する
これはmdnに書いてある通りにできます。
URL.createObjectURL(object)
ObjectURLからBlobへ変換する
fetchを使ってURLからファイルをダウンロードした後に変換して使えます。
export const objectURLToBlob = async (objectURL: string) => { const respnse = await fetch(objectURL) const blob = await respnse.blob() return blob }