ブラウザからJSONオブジェクトをファイルとしてダウンロードする


144

ユーザーがcsvファイルのデータ文字列をダウンロードできるようにする次のコードがあります。

exportData = 'data:text/csv;charset=utf-8,';
exportData += 'some csv strings';
encodedUri = encodeURI(exportData);
newWindow = window.open(encodedUri);

クライアントがコードを実行すると空白ページが生成され、csvファイル内のデータのダウンロードが開始されるので、問題なく機能します。

だから私はJSONオブジェクトでこれをやろうとしました

exportData = 'data:text/json;charset=utf-8,';
exportData += escape(JSON.stringify(jsonObject));
encodedUri = encodeURI(exportData);
newWindow = window.open(encodedUri);

しかし、JSONデータが表示されたページのみが表示され、ダウンロードはされません。

私はいくつかの調査を行いましたが、これは機能すると主張していますが、コードに違いはありません。

コードに何か不足していますか?

私の質問を読んでくれてありがとう:)

回答:


257

これは私が私のアプリケーションのためにそれを解決した方法です:

HTML: <a id="downloadAnchorElem" style="display:none"></a>

JS(ここではjQueryではなく純粋なJS):

var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(storageObj));
var dlAnchorElem = document.getElementById('downloadAnchorElem');
dlAnchorElem.setAttribute("href",     dataStr     );
dlAnchorElem.setAttribute("download", "scene.json");
dlAnchorElem.click();

この場合、storageObjは保存するjsオブジェクトであり、「scene.json」は結果のファイルの名前の例にすぎません。

このアプローチには、他の提案されたアプローチよりも次の利点があります。

  • HTML要素をクリックする必要はありません
  • 結果はあなたが望むように名前が付けられます
  • jQueryは不要

jsのある時点でダウンロードを自動的にトリガーしたいので、明示的なクリックなしでこの動作が必要でした。

JSソリューション(HTMLは不要):

  function downloadObjectAsJson(exportObj, exportName){
    var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(exportObj));
    var downloadAnchorNode = document.createElement('a');
    downloadAnchorNode.setAttribute("href",     dataStr);
    downloadAnchorNode.setAttribute("download", exportName + ".json");
    document.body.appendChild(downloadAnchorNode); // required for firefox
    downloadAnchorNode.click();
    downloadAnchorNode.remove();
  }

3
これは、=〜2000文字を超えるデータに対して機能する唯一のソリューションです。先頭にデータを追加したため:
rjurney

1
誰かがこの先頭に追加されたデータ型のものがどのように機能するか、つまり詳細を説明するスペックまたはMDNページを私に指摘できますか?"data:text / json; charset = utf-8"?私はこれを使用していますが、それは魔法のように感じられ、詳細を読むのは素晴らしいことですが、それをググる方法すら知りません。
sidewinderguy

1
これはIEでは機能しませんが、2000文字を超える大きなファイルをダウンロードする必要があります。
user388969

12
ただし、これは制限なしでは機能しません。ダウンロードできるデータは約1MBです。たとえばvar storageObj = []; for (var i=0; i<1000000; ++i) storageObj.push('aaa');、Chrome 61で「ダウンロード失敗-ネットワークエラー」と表示される
oseiskar

1
@YASHDAVEをJSON.stringify(exportObj, null, 2)代わりに使用
TryingToImprove

40

答えが見つかりました。

var obj = {a: 123, b: "4 5 6"};
var data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(obj));

$('<a href="data:' + data + '" download="data.json">download JSON</a>').appendTo('#container');

私にとってはうまくいくようです。

**すべてのクレジットは、上記のコードの作成者である@ cowboy-ben-almanに送られます**


@ Cybear、3行目を説明してくれませんか?
Rahul Khatri

データを先頭に追加する必要があります。URLに追加しないと、ユーザーは多くのブラウザで2000文字の制限に達する可能性があります。
rjurney 2016

ねえ、私はそれが古い答えであることを知っていますが、このソリューションがIE(それらすべて)で機能しないことを知っていますIEはダウンロード属性リファレンスに精通していません- リンク
Ayalon Grinfeld

25

これは純粋なJSバージョンになります(カウボーイのものから変更):

var obj = {a: 123, b: "4 5 6"};
var data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(obj));

var a = document.createElement('a');
a.href = 'data:' + data;
a.download = 'data.json';
a.innerHTML = 'download JSON';

var container = document.getElementById('container');
container.appendChild(a);

http://jsfiddle.net/sz76c083/1


3
私がこの質問をしてから2年間が経過した後でも応答をありがとう!私はjQuery構文よりも純粋なJSを好みます。
Eugene Yu

データを先頭に追加する必要があります。URLに追加しないと、ユーザーは多くのブラウザで2000文字の制限に達する可能性があります。
rjurney 2016

ページの読み込み時にこのダウンロードを開始するにはどうすればよいですか。ユーザーがページのURLを閲覧するたびにダウンロードのプロンプトが表示される
user388969

1
Edgeでの本日のテスト:data.jsonをダウンロードできませんでした。
Sarah Trees

24

あなたは使用してみることができます:

  • ネイティブJavaScript APIのBlobコンストラクター
  • FileSaver.js saveAs()方法

HTML要素をまったく扱う必要はありません。

var data = {
    key: 'value'
};
var fileName = 'myData.json';

// Create a blob of the data
var fileToSave = new Blob([JSON.stringify(data)], {
    type: 'application/json',
    name: fileName
});

// Save the file
saveAs(fileToSave, fileName);

JSONをきれいに出力したい場合は、この回答に従って、次のように使用できます。

JSON.stringify(data,undefined,2)

1
saveAs()FileSaver.jsからである- github.com/eligrey/FileSaver.js
Gautham

1
「HTML要素をまったく扱う必要がない」...そして、filesaver.jsのソースコードを読む...それはまさにその通りです
War

1
うん。つまり、HTML要素を直接処理する必要はありません。
Gautham 2017

3
1MBのサイズ制限がなく、カスタムハックの代わりにライブラリを使用するため、これが最良の答えです
oseiskar

FileSaver refに賛成投票 完璧に働いています。
ヌーン

15

以下は私のために働きました:

/* function to save JSON to file from browser
* adapted from http://bgrins.github.io/devtools-snippets/#console-save
* @param {Object} data -- json object to save
* @param {String} file -- file name to save to 
*/
function saveJSON(data, filename){

    if(!data) {
        console.error('No data')
        return;
    }

    if(!filename) filename = 'console.json'

    if(typeof data === "object"){
        data = JSON.stringify(data, undefined, 4)
    }

    var blob = new Blob([data], {type: 'text/json'}),
        e    = document.createEvent('MouseEvents'),
        a    = document.createElement('a')

    a.download = filename
    a.href = window.URL.createObjectURL(blob)
    a.dataset.downloadurl =  ['text/json', a.download, a.href].join(':')
    e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
    a.dispatchEvent(e)
}

そしてそれをそのように呼ぶ

saveJSON(myJsonObject, "saved_data.json");

3
これは素晴らしい答えですが、これは非推奨の Web標準でありinitMouseEvent()今後は使用しないでください。代わりに、new MouseEvent()インターフェースを使用してください。ただし、これはマイナーなリファクタリングです。
morkro

10

私は最近、大きなフォームのすべての値のjsonファイルをダウンロードするボタンを作成する必要がありました。IE / Edge / Chromeで使用するには、これが必要でした。これは私がやったことです:

function download(text, name, type)
    {
        var file = new Blob([text], {type: type});
        var isIE = /*@cc_on!@*/false || !!document.documentMode;
        if (isIE)
        {
            window.navigator.msSaveOrOpenBlob(file, name);
        }
        else
        {
            var a = document.createElement('a');
            a.href = URL.createObjectURL(file);
            a.download = name;
            a.click();
        }
     }

download(jsonData, 'Form_Data_.json','application/json');

Edgeのファイル名と拡張子に1つの問題がありましたが、これを書いている時点では、これはEdgeのバグであると思われ、修正される予定です。

これが誰かを助けることを願っています


これはChromeでは機能しましたが、Firefoxでは機能しないようです...助けてください!codepen.io/anon/pen/ePYPJb
ウルミルパリク

1
素敵な機能、document.body.appendChild(a); a.style.display = 'none';Firefoxで動作させるために追加します。
Fabian von Ellerts

5

最新のブラウザのみを対象とするユーザー向けのシンプルでクリーンなソリューション:

function downloadTextFile(text, name) {
  const a = document.createElement('a');
  const type = name.split(".").pop();
  a.href = URL.createObjectURL( new Blob([text], { type:`text/${type === "txt" ? "plain" : type}` }) );
  a.download = name;
  a.click();
}

downloadTextFile(JSON.stringify(myObj), 'myObj.json');

ありがとう、サイズの問題が発生しなかった1つだけ
Roelant


2

React:これをレンダーメソッドの必要な場所に追加します。

状態のオブジェクト:

<a
  className="pull-right btn btn-primary"
  style={{ margin: 10 }}
  href={`data:text/json;charset=utf-8,${encodeURIComponent(
  JSON.stringify(this.state.objectToDownload)
  )}`}
  download="data.json"
>
  DOWNLOAD DATA AS JSON
</a>

小道具のオブジェクト:

<a
  className="pull-right btn btn-primary"
  style={{ margin: 10 }}
  href={`data:text/json;charset=utf-8,${encodeURIComponent(
  JSON.stringify(this.props.objectToDownload)
  )}`}
  download="data.json"
>
  DOWNLOAD DATA AS JSON
</a>

classNameとstyleはオプションです。必要に応じてスタイルを変更してください。


1

別のMIMEタイプを設定してみてください。 exportData = 'data:application/octet-stream;charset=utf-8,';

ただし、保存ダイアログのファイル名に問題がある可能性があります。


遅れて戻ってきてすみません。私はあなたの答えを試してみましたが、ファイルをダウンロードしましたが、その中に誤ったデータが含まれています.. :(
Eugene Yu

1
これは私にとってはうまくいきました... data = "data:application/octet-stream;charset=utf-8," + encodeURIComponent(JSON.stringify(data)); window.open(data); それは単に「ダウンロード」としてファイルをダウンロードしますが、データを文字列化してからuriエンコードする必要があります。
Jason Wiener

0

ファイル名よりもコンソールスニペット、raserを使用する場合は、次のようにできます。

window.open(URL.createObjectURL(
    new Blob([JSON.stringify(JSON)], {
      type: 'application/binary'}
    )
))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.