File API周りを整理してみた

CSVデータをインポートする実装で、FileAPI周りでBlobとかArrayBufferとかよく見かける、名前だけ知ってるもの達を整理してみた。

## CSVとは
そもそもCSVファイルとは、`Comma Separated Values`の略で、各項目がカンマ（,）で区切られたテキストデータのことです。データの容量が軽く、読み書きや編集が容易であるという特徴があります。

CSVファイルとExcelファイルの最も大きな違いは「互換性が高いか、装飾・機能の自由度が高いか」ということです。

拡張子「.csv」のCSVファイルは互換性が高く、Excelのみならずメモ帳、メールソフト、データベースソフトなどほとんどのソフトに取り込んで閲覧、編集することが可能です。そのため、Excelファイルを扱えるかが不明な相手とデータのやり取りを行う際はCSVに変換される場合が多いです。

[データのじかん](https://data.wingarc.com/csv-excel-2-19747#CSV) から引用



## FIle API
FIle API は、ウェブアプリケーションがローカルマシンにあるファイルへアクセスしてJavaScriptで操作できるようにするためのAPIです。

その中の1つである**FileReader**を使って、アップロード、インポートなどが行われる

### FileReader API
その名の通り、Fileオブジェクトを実際に読み込む

**読み込みメソッド**
`readAsArrayBuffer` : ファイルをArrayBufferとして読み込む
`readAsText` : ファイルをテキストとして読み込む
`readAsDataURL` : ファイルをDataURLとして読み込む
`readAsBinaryString` : ファイルをバイナリ形式で読み込む

#### サンプル
CSVをインポートする流れを以下のライブラリを用いて実装するサンプルです。

使用ライブラリ
`ExcelJS` : JSでExcelファイルを扱うようにできるライブラリ
`Stream-Browserify` : NodeのストリームAPIをブラウザで動かすライブラリ

ExcelJSのCSV読み込みの仕様
`stream`で渡さないといけない (以下ドキュメントより引用)
```typescript
// read from a stream
const workbook = new Excel.Workbook();
const worksheet = await workbook.csv.read(stream);
```

以下CSVファイルをインポートして、streamに変換し、ExcelJSに渡すまでのサンプルです。
```typescript
// JSでExcelファイルを扱うようにできるライブラリ
import ExcelJS from 'exceljs'
// NodeのストリームAPIをブラウザで動かすライブラリ
import { Readable } from 'stream-browserify'
import { Buffer } from 'buffer'


// グローバルスコープで利用できるのでインポートしなくても利用できる
const reader = new FileReader();
// リーダーにファイルをArrayBufferとして読み込む
reader.readAsArrayBuffer(file);
// 読み込みが成功して完了したら、以下のonloadメソッド内で読み込み結果が見れる
// この場合はArrayBufferデータ
reader.onload = () => {
  // リーダーがArrayBufferで読み込んだデータ
  const contents = reader.result
    
  // ExcelJSのインスタンスを作成
  const workbook = new ExcelJS.Workbook()
    
  // ArrayBufferをBufferObjectに変換
  const buffer = Buffer.from(contents)
    
  // ExcelJSがストリームからデータを読み取れるようにする
  const stream = new Readable()
  stream.push(buffer)
    
  // ストリームの終了
  stream.push(null)
    
  // ExcelJSのCSVリーダーにストリームを渡す
  await workbook.csv.read(stream)

  return workbook.worksheets
}
```

処理フローをまとめると
・ユーザーがFileを選択
・FileをArrayBufferとして読み込む
・読み込みが完了したら、resultプロパティにArrayBufferが格納される
・ArrayBufferをBufferに変換する
・BufferをReadable Streamに変換する
・Readable StreamをExcelJSのCSVリーダーメソッドに渡すと、JSで扱えるデータにしてくれる

## JavaScriptで扱えるバイナリデータ
ArrayBuffer, Uint8Array, DataView, Blob, File, etc.
基本となるバイナリオブジェクトは ArrayBuffer です。これは固定長の連続したメモリ領域への参照です。

### バイナリデータとは
0と1の2進数で表現されるデータのことを指します。コンピューターはこの形式のデータを扱うことが得意であり、多くのデータがバイナリーデータとして保存されます。例えば、画像、音声、動画、プログラムなどがバイナリーデータの形式で保存されています。

### 1. ArrayBuffer
JavaScript でバイナリデータを扱うときには ArrayBuffer を使うのが便利です。 ArrayBuffer は固定長のバイナリデータバッファを表します。
File API の FileReader などはデータを読み取った結果を ArrayBuffer として返します。そのため 「バイナリデータを使う時は ArrayBuffer を活用する」と覚えておくと、わかりやすいです。

> ArrayBuffer は Array とは何の共通点もありませんので、配列データではない。
長さは固定で、増減することはできません。
メモリの中で、長さちょうどのスペースをとります。
個々のバイトにアクセスするには、buffer[index] ではなく、別の “view” オブジェクトが必要です。

### 2. Blob
BlobはBinary Large Objectの略
一般的なバイナリデータをJavaScriptで扱えるようにしたり、新しく生成することができます。

バイナリデータを簡単に説明すると「0」と「1」で表現される2進数だけでテキストや画像などをデータ化したものになります。また、Blobを拡張してブラウザ上からファイルを読み込んだりダウンロードするFile APIも一緒によく使われます。

JavaScriptのネイティブフォーマットではないデータを表すために使用されます。簡単に言うと、Blobは画像、zipファイル、オーディオファイルなど、さまざまなタイプのデータを扱うために使われます。

### 3. File
ファイルについての情報を提供したり、ウェブページ内の JavaScript からその内容にアクセスできるようにしたりします。Blobを継承してる

### 4. Buffer
Node.jsでは、文字列とバイナリデータ（バイト列）はまったく別のものとして扱われる。前者を扱うためのクラスがStringで、後者を扱うNode.js独自のクラスがBuffer。
Node.jsでは文字列とバイト列は厳密に区別されており、文字列の格納にはStringクラスを、バイト列の格納にはBufferクラスを利用するようになっている。

## ストリームAPI
データを逐次的に読み込みながら処理したいときに利用するAPI
以下の３つの要素がある
ReadableStream データソースからデータを読み出してストリームとして提供する
TransformStream ストリームから受け取ったデータを変換してストリームとして提供する
WritableStream ストリームから受け取ったデータをデータソースに書き込む