Unduh objek JSON sebagai file dari browser

144

Saya memiliki kode berikut untuk memungkinkan pengguna mengunduh string data dalam file csv.

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

Ini berfungsi dengan baik bahwa jika klien menjalankan kode itu menghasilkan halaman kosong dan mulai mengunduh data dalam file csv.

Jadi saya mencoba melakukan ini dengan objek JSON seperti

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

Tapi saya hanya melihat halaman dengan data JSON yang ditampilkan di sana, bukan mengunduhnya.

Saya telah melalui beberapa penelitian dan yang satu ini mengklaim berfungsi tetapi saya tidak melihat perbedaan pada kode saya.

Apakah saya kehilangan sesuatu dalam kode saya?

Terima kasih sudah membaca pertanyaan saya :)

Eugene Yu
sumber

Jawaban:

257

Ini adalah bagaimana saya menyelesaikannya untuk aplikasi saya:

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

JS (JS murni, bukan jQuery di sini):

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();

Dalam hal ini, storageObjadalah objek js yang ingin Anda simpan, dan "scene.json" hanyalah nama contoh untuk file yang dihasilkan.

Pendekatan ini memiliki keunggulan berikut dibandingkan yang diusulkan lainnya:

  • Tidak ada elemen HTML yang perlu diklik
  • Hasil akan dinamai sesuai keinginan Anda
  • tidak perlu jQuery

Saya memerlukan perilaku ini tanpa mengklik eksplisit karena saya ingin memicu unduhan secara otomatis di beberapa titik dari js.

Solusi JS (tidak perlu 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();
  }
volzotan
sumber
3
Ini adalah satu-satunya solusi yang akan bekerja untuk lebih dari = ~ 2000 karakter data. Karena Anda menambahkan data:
rjurney
1
Adakah yang bisa mengarahkan saya ke halaman spec atau MDN yang menjelaskan secara lebih terperinci bagaimana semua tipe data yang didukung ini berfungsi. "data: text / json; charset = utf-8"? Saya menggunakan ini, tetapi rasanya seperti sulap, akan sangat bagus untuk membaca detailnya tetapi saya bahkan tidak tahu cara google untuk itu.
sidewinderguy
1
Ini tidak bekerja di IE ketika Anda harus mengunduh file besar dengan lebih dari 2000 karakter.
user388969
12
Ini tidak akan bekerja tanpa batas. Anda hanya dapat mengunduh sekitar 1MB data. Misalnya, var storageObj = []; for (var i=0; i<1000000; ++i) storageObj.push('aaa');beri "unduh Gagal - Kesalahan jaringan" di Chrome 61
oseiskar
1
@YASHDAVE gunakan JSON.stringify(exportObj, null, 2)sebagai gantinya
TryingToImprove
40

Menemukan jawaban.

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');

sepertinya bekerja dengan baik untuk saya.

** Semua kredit diberikan kepada @ cowboy-ben-alman, yang merupakan pembuat kode di atas **

Eugene Yu
sumber
@Cybear, bisakah Anda menjelaskan baris ketiga kepada saya?
Rahul Khatri
Anda ingin menambahkan data: ke url Anda, jika tidak, pengguna mungkin akan mencapai batas 2000 karakter di banyak browser.
rjurney
Hai, saya tahu ini adalah jawaban yang lama tetapi, tahu solusi ini tidak bekerja pada IE (semuanya) IE tidak terbiasa dengan referensi atribut unduhan - tautan
Ayalon Grinfeld
25

Ini akan menjadi versi JS murni (diadaptasi dari koboi):

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

jbcdefg
sumber
3
Terima kasih atas tanggapannya bahkan setelah 2 tahun sejak saya mengajukan pertanyaan ini! Saya lebih suka JS murni daripada sintaks jQuery.
Eugene Yu
Anda ingin menambahkan data: ke url Anda, jika tidak, pengguna mungkin akan mencapai batas 2000 karakter di banyak browser.
rjurney
bagaimana saya bisa membuat unduhan ini dimulai pada pemuatan halaman. setiap kali seorang pengguna menelusuri halaman url ia mendapat prompt untuk mengunduh
user388969
1
Tes hari ini di Edge: data.json tidak dapat diunduh.
Sarah Trees
24

Anda dapat mencoba menggunakan:

Tidak perlu berurusan dengan elemen HTML sama sekali.

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);

Jika Anda ingin cukup mencetak JSON, per jawaban ini , Anda dapat menggunakan:

JSON.stringify(data,undefined,2)
Gautham
sumber
1
saveAs () berasal dari FileSaver.js - github.com/eligrey/FileSaver.js
Gautham
1
"Tidak perlu berurusan dengan elemen HTML sama sekali" ... dan membaca kode sumber filesaver.js ... itu persis seperti itu lol
War
1
Ya. Saya bermaksud mengatakan, tidak perlu berurusan dengan elemen HTML secara langsung.
Gautham
3
Ini adalah jawaban terbaik karena tidak memiliki batas ukuran 1MB dan menggunakan pustaka alih-alih peretasan khusus
oseiskar
terpilih untuk FileSaver ref. bekerja dengan sempurna.
Noone
15

Berikut ini bekerja untuk saya:

/* 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)
}

dan kemudian menyebutnya seperti itu

saveJSON(myJsonObject, "saved_data.json");
maia
sumber
3
Meskipun ini adalah jawaban yang bagus, initMouseEvent()adalah Standar Web yang sudah usang dan tidak boleh digunakan lagi. Sebagai gantinya, gunakan new MouseEvent()antarmuka. Itu hanya refactor kecil.
morkro
10

Baru-baru ini saya harus membuat tombol yang akan mengunduh file json dari semua nilai bentuk besar. Saya membutuhkan ini untuk bekerja dengan IE / Edge / Chrome. Inilah yang saya lakukan:

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');

Ada satu masalah dengan nama file dan ekstensi di tepi tetapi pada saat penulisan ini tampaknya menjadi bug dengan Ujung yang akan diperbaiki.

Semoga ini bisa membantu seseorang

Brad
sumber
Ini berfungsi di Chrome, tetapi sepertinya tidak berfungsi di Firefox ... tolong bantu! codepen.io/anon/pen/ePYPJb
Urmil Parikh
1
Fungsi yang bagus, tambahkan document.body.appendChild(a); a.style.display = 'none';untuk membuatnya bekerja di Firefox.
Fabian von Ellerts
5

Solusi sederhana dan bersih bagi mereka yang hanya menargetkan browser modern:

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');
user993683
sumber
Terima kasih, hanya satu yang tidak memberi saya masalah ukuran
Roelant
4

The downloadproperti link baru dan tidak didukung di Internet Explorer (lihat tabel kompatibilitas di sini ). Untuk solusi lintas-browser untuk masalah ini saya akan melihat FileSaver.js

robertjd
sumber
2

Bereaksi : tambahkan ini di tempat yang Anda inginkan dalam metode render Anda.

• Objek dalam keadaan :

<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>

• Objek dalam alat peraga :

<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 dan gaya adalah opsional, modifikasi gaya sesuai dengan kebutuhan Anda.

Abido
sumber
1

Cobalah untuk mengatur tipe MIME lain: exportData = 'data:application/octet-stream;charset=utf-8,';

Tetapi mungkin ada masalah dengan nama file dalam dialog simpan.

minimulin
sumber
Maaf sudah terlambat kembali. Saya mencoba jawaban Anda dan tidak mengunduh file tetapi berisi data yang salah di dalamnya .. :(
Eugene Yu
1
ini bekerja untuk saya ... data = "data:application/octet-stream;charset=utf-8," + encodeURIComponent(JSON.stringify(data)); window.open(data); itu hanya mengunduh file sebagai "unduh" tetapi data yang saya ikat dan kemudian uri-disandikan sebagaimana mestinya.
Jason Wiener
0

Jika Anda lebih suka potongan konsol, raser, daripada nama file, Anda dapat melakukan ini:

window.open(URL.createObjectURL(
    new Blob([JSON.stringify(JSON)], {
      type: 'application/binary'}
    )
))
zb '
sumber