flow-flow-flow

[JavaScript] APIからレスポンスでうけっとたファイルデータをローカルのディレクトリに保存したいならbase64してさらにBufferに変換すればよかった

f:id:thegriftsense:20210822225438j:plain

困ったこと

electronでアプリを作っていて、サーバから取得したファイルをwindows pc のAppData/localLow/{appName}に保存する必要がでてきた。自分としてはレスポンスをresponse.blob()として、そのまま fs.writeFileSync(path, value);で保存できると思っていたけど、うまくいかなかった。そこで一個前の案件でも同じような処理があって、その実装を上司がしていたのを思い出してそのソースコードを真似したらちゃんと保存できた。とはいえ上司のコードがなにをしているのかいまいち理解できなかったので調べてまとめておこうともう。

なんかblobをbase64に変換してから保存するらしい

とりあえずコード(自分なりにちょっと変更してる。上司のコードはbase64に変換する処理が関数化されててもっと綺麗)

const response = await fetch('', { method: "GET" });
const blob = await response.blob();
const reader = new FileReader();
reader.onload = () => {
  const base64 = (reader.result as string).split(',')[1];
  const buffer = new Buffer(await this.blobToBase64(v as any), 'base64');
  fs.writeFileSync('./example.txt', buffer);
};
reader.readAsDataURL(blob);

はいはいblobをbase64にしてdata部分を保存するわけですね(自己解決)

ソースコードを見るとレスポンスをblobに変換して、それをさらにbase64に変換してから保存しているらしい。 そういえばこの記事でもreadAdDataURLを使ってたなあ。 でも前はFileオブジェクトをbase64に変換したのであって、今回はBlobオブジェクトの変換。FileオブジェクトとBlobオブジェクトについて自分はほとんどなにも知らないことに思い当たったので、ざっと調べてみるとこんな記述があった。

File オブジェクトは特別な種類の Blob オブジェクトであり、 Blob が利用できる場面ではどこでも利用できます。

へえである。FileオブジェクトはBlobオブジェクトを継承しているみたいな認識でいいのかな?

ところで(reader.result as string).split(',')[1]この部分の処理はなにをしているのだろうか。 と思ったけど、これURLスキームの頭のbata:[<mediatype>][;base64],<data><data>部分だけを取り出してるのか。なるほど。コピペしてるときはなんのことかわからなかったけどいま書いてたら一瞬で理解できてしまった。やったぜ。

ということはつまり、レスポンスで受け取ったファイルをローカルのディレクトリに保存するときは、blobをbase64にしてdata部分をさらにBufferに変換して保存してやればいいということか。おおおお理解できたーーー!

なんかBlobオブジェクトとFileオブジェクトとDataUrlスキーマbase64について少し理解できた気がする。

new Buffer() よりも Buffer.from()の方がいい?

いろんな記事を読んでたら、new Buffer() は脆弱性があるから非推奨だよ! Buffer.from()使おうね! みたいな記事がたくさんあったので、Buffer.from() のほうがいいかも。

おわり。

参考