JSON nesnesini tarayıcıdan bir dosya olarak indir


144

Kullanıcıların csv dosyasında veri dizeleri indirmesine izin vermek için aşağıdaki kodu var.

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

İstemci kodu çalıştırırsa boş sayfa oluşturur ve csv dosyasındaki verileri indirmeye başlar.

Bu yüzden JSON nesnesi ile bunu yapmaya çalıştım

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

Ancak yalnızca JSON verilerinin görüntülendiği bir sayfa görüyorum, indirmiyorum.

Biraz araştırma yaptım ve bunun işe yaradığını iddia ediyor ama kodumda herhangi bir fark görmüyorum.

Kodumda bir şey mi eksik?

Sorumu okuduğunuz için teşekkürler :)

Yanıtlar:


257

Uygulamam için şu şekilde çözdüm:

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

JS (saf JS, burada jQuery değil):

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

Bu durumda, storageObjsaklamak istediğiniz js nesnesidir ve "scene.json" yalnızca sonuçta elde edilen dosya için örnek bir addır.

Bu yaklaşım, önerilen diğer yaklaşımlara göre aşağıdaki avantajlara sahiptir:

  • HTML öğesinin tıklanmasına gerek yoktur
  • Sonuç istediğiniz gibi adlandırılacaktır
  • jQuery gerekmez

Ben js bir noktada otomatik olarak indirme tetiklemek istiyorum beri açık tıklama olmadan bu davranış gerekli.

JS çözümü (HTML gerekmez):

  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 karakterden fazla veri için çalışacak tek çözüm budur. Verileri tercih ettiğiniz için:
rjurney

1
Birisi beni tüm bu önceden veri türü şey yani nasıl çalıştığını daha ayrıntılı açıklayan bir spec veya MDN sayfasına işaret edebilir. "veriler: metin / json; charset = UTF-8"? Bunu kullanıyorum, ama sihir gibi geliyor, detayları okumak harika olurdu ama bunun için nasıl google'ı bile bilmiyorum.
sidewinderguy

1
2000'den fazla karakter içeren büyük bir dosya indirmeniz gerektiğinde bu IE'de çalışmaz.
user388969

12
Ancak bu sınırlar olmadan çalışmaz. Yalnızca yaklaşık 1 MB veri indirebilirsiniz. Örneğin, var storageObj = []; for (var i=0; i<1000000; ++i) storageObj.push('aaa');Chrome 61'de "indirme Başarısız - Ağ hatası" veriyor
oseiskar

1
@YASHDAVE kullanım JSON.stringify(exportObj, null, 2)yerine
TryingToImprove

40

Bir cevap buldum.

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

benim için iyi çalışıyor gibi görünüyor.

** Tüm krediler yukarıdaki kodun yazarı olan @ cowboy-ben-alman'a gider **


@Cybear bana üçüncü satırı açıklayabilir misin?
Rahul Khatri

Verilerin başına URL eklemek isteyeceksiniz: Aksi takdirde, kullanıcının birçok tarayıcıda 2000 karakter sınırına ulaşması muhtemeldir.
rjurney

Hey, eski bir cevap olduğunu biliyorum, ama biliyorum bu çözüm IE (hepsi) üzerinde çalışmaz IE indirme özniteliği referans aşina değil - bağlantı
Ayalon Grinfeld

25

Bu saf bir JS versiyonu olacak (kovboydan uyarlanmış):

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
Bu soruyu sordum 2 yıl sonra bile yanıt için teşekkürler! Saf JS jQuery sözdizimi tercih ederim.
Eugene Yu

Verilerin başına URL eklemek isteyeceksiniz: Aksi takdirde, kullanıcının birçok tarayıcıda 2000 karakter sınırına ulaşması muhtemeldir.
rjurney

bu indirmeyi sayfa yüklemesinde nasıl başlatabilirim? ne zaman bir kullanıcı sayfa url göz atmak için o istemi alır
user388969

1
Edge'deki bugünkü test: data.json indirilemedi.
Sarah Trees

25

Kullanmayı deneyebilirsiniz:

  • yerel JavaScript API'sının Blob yapıcısını ve
  • FileSaver.js saveAs() yöntemi

Herhangi bir HTML öğesiyle uğraşmanıza gerek yok.

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'u oldukça yazdırmak istiyorsanız, bu cevap başına şunları kullanabilirsiniz:

JSON.stringify(data,undefined,2)

1
saveAs (), FileSaver.js'den - github.com/eligrey/FileSaver.js
Gautham

1
"Hiç HTML öğeleri ile uğraşmak gerek yok" ... ve filesaver.js kaynak kodunu okumak ... tam olarak bunu yapar lol
Savaş

1
Evet. Demek istediğim, doğrudan HTML elemanları ile uğraşmaya gerek yok.
Gautham

3
Bu, 1MB boyut sınırına sahip olmadığından ve özel kesmek yerine bir kitaplık kullandığı için en iyi yanıttır
oseiskar

FileSaver için oy kullandı ref. mükemmel çalışıyor.
Noone

15

Aşağıdakiler benim için çalıştı:

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

ve sonra böyle çağırmak için

saveJSON(myJsonObject, "saved_data.json");

3
Bu büyük bir cevabı iken, initMouseEvent()bir olduğunu kaldırılmış Web Standardı ve artık kullanılmaması gerekir. Bunun yerine new MouseEvent()arayüzü kullanın . Bu sadece küçük bir refactor olsa.
morkro

10

Son zamanlarda büyük bir formun tüm değerlerinin bir json dosyasını indirmek bir düğme oluşturmak zorunda kaldı. IE / Edge / Chrome ile çalışmak için buna ihtiyacım vardı. Ben de öyle yaptım:

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

Dosya adı ve uzantı uzantısı ile ilgili bir sorun vardı, ancak yazma sırasında bu, düzeltilmesi gereken Edge ile ilgili bir hata gibi görünüyordu.

Umarım bu birine yardımcı olur


Bu Chrome'da çalıştı, ancak Firefox'ta çalışmıyor gibi görünüyor ... lütfen yardım edin! codepen.io/anon/pen/ePYPJb
Urmil Parikh

1
Güzel bir işlev, document.body.appendChild(a); a.style.display = 'none';Firefox'ta çalışmasını sağlamak için ekleyin .
Fabian von Ellerts

5

Yalnızca modern tarayıcıları hedefleyen kullanıcılar için basit, temiz bir çözüm:

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

Teşekkürler, bana boyut sorunları vermeyen tek kişi
Roelant

4

downloadBağlantıların özelliği (uyumluluk tabloya bakınız yeni olup Internet Explorer'da desteklenir ise burada ). Bu soruna çapraz tarayıcı çözümü için FileSaver.js'ye bir göz atacağım


2

React : bunu render yönteminizde istediğiniz yere ekleyin.

• Nesne durumda :

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

Sahne içindeki nesne :

<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 ve stil isteğe bağlıdır, stili ihtiyaçlarınıza göre değiştirin.


1

Başka bir MIME türü ayarlamayı deneyin: exportData = 'data:application/octet-stream;charset=utf-8,';

Ancak kaydet iletişim kutusunda dosya adıyla ilgili sorunlar olabilir.


Sana geç döndüğüm için üzgünüm. Cevabınızı denedim ve dosya indiriyor, ancak yanlış veri içeriyor .. :(
Eugene Yu

1
Bu benim için çalıştı ... data = "data:application/octet-stream;charset=utf-8," + encodeURIComponent(JSON.stringify(data)); window.open(data); sadece dosyayı "indirmek" olarak indirir ama i stringize ve sonra uri kodlanmış veri olması gerektiği gibi.
Jason Wiener

0

Konsol snippet, raser, dosya adından daha fazla tercih ederseniz, bunu yapabilirsiniz:

window.open(URL.createObjectURL(
    new Blob([JSON.stringify(JSON)], {
      type: 'application/binary'}
    )
))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.