msSaveBlob,Data URI SchemeおよびURL.createObjectURLによるデータ保存

# msSaveBlob,Data URI SchemeおよびURL.createObjectURLによるデータ保存

jsでデータ保存(download)する方法として以下の方法を試す

<dl>
<dt>navigator.msSaveBlob</dt>
<dd>
利用できるのはIEだけ(Blob と `navigator.msSaveBlob` を使ってファイルをローカルに保存する)

```js
var blob = new Blob(["blobデータ"]);
window.navigator.msSaveBlob(blob, "filename.txt"); //ダウンロードダイアログが表示
```

Blobデータをダウンロードフォルダに保存する。`navigator.msSaveOrOpenBlob`という関数もあり、こちらはすぐ開くか保存するかを選択する。
</dd>
<dt>Data URI Scheme</dt>
<dd>
多くのブラウザで動作する

`<a href="data:application/octet-stream;base64,..." download="filename.txt">download</a>` をクリックさせることでダウンロード。Base64化したデータを直接記述する。

```js
var data = "Data URI Schemeによるダウンロード",
	base64 = btoa(unescape(encodeURIComponent(data))),
	a = document.createElement('A');
a.download = 'filename.txt';
a.href = 'data:application/octet-stream;base64,' + encodeURIComponent(base64);
document.body.appendChild(a);
a.click(); //自動ダウンロード
document.body.removeChild(a);
```

リンク先のURLはデータの長さに比例(4/3倍)する。データが大きいとメモリを大量消費する
</dd>
<dt>URL.createObjectURL</dt>

利用できるのはwindow.URLがあるブラウザのみ([URL.createObjectURL() - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL))

`URL.createObjectURL(file)` とすると、ブラウザがBlobデータをランダムな値がついたobjectURLに変換する

```js
var data = "URL.createObjectURL()によるダウンロード",
	url = URL.createObjectURL(new Blob([data])),
	a = document.createElement('A');
alert(url);
a.download = 'filename.txt';
a.href = url;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
```

こちらは大きいデータでも快適に動作する。IEの場合、ローカルな環境(file://...)では動作しない

## 切り替えて利用する

1. msSaveBlobが利用可能なら使う
2. 不可の場合、URL.createObjectURL()を利用可能ならば使う
3. どちらも不可の場合はData URI Schemeを利用する

```js
var saveText = function(str, filename) {
	var uri, a;
	if (navigator.msSaveBlob) {
		navigator.msSaveBlob(new Blob([str]), filename);
		return;
	}
	if (window.URL && window.URL.createObjectURL) {
		uri = URL.createObjectURL(new Blob([str]));
	} else {
		uri = 'data:application/octet-stream;base64,' +
			encodeURIComponent(btoa(unescape(encodeURIComponent(str))));;
	}
	a = document.createElement('A');
	a.href = uri;
	a.download = filename;
	document.body.appendChild(a);
	a.click();
	document.body.removeChild(a);
};

saveText("保存したいテキスト", "filename.txt");
```

テキストだけではなく任意のデータ(バイト列)を保存したい場合には多少工夫が必要になる。 具体的には、Data URI Schemeの作成時の処理が変化している。 非同期実行にはなるが、この部分にBlobと`FileReader.prototype.readAsDataURL()`を使用してもよい。

```js
var saveBytes = function(bytes, filename) {
	var uri, a;
	if (navigator.msSaveBlob) {
		navigator.msSaveBlob(new Blob([new Uint8Array(bytes)]), filename);
		return;
	}
	if (window.URL && window.URL.createObjectURL) {
		uri = URL.createObjectURL(new Blob([new Uint8Array(bytes)]));
	} else {
		uri = 'data:application/octet-stream;base64,' +
			encodeURIComponent(btoa(String.fromCharCode.apply(null, bytes)));;
	}
	a = document.createElement('A');
	a.href = uri;
	a.download = filename;
	document.body.appendChild(a);
	a.click();
	document.body.removeChild(a);
};
saveBytes(
	[137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,1,0,0,0,1,8,6,0,0,0,31,21,196,137,0,0,0,13,73,68,65,84,8,153,99,96,96,96,96,0,0,0,5,0,1,135,161,78,212,0,0,0,0,73,69,78,68,174,66,96,130],
	"spacer.png"
); //1x1 PNG
```