Pobierz obiekt JSON jako plik z przeglądarki


144

Mam następujący kod, aby umożliwić użytkownikom pobieranie ciągów danych w pliku csv.

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

Działa dobrze, jeśli klient uruchamia kod, generuje pustą stronę i rozpoczyna pobieranie danych w pliku csv.

Więc próbowałem to zrobić z obiektem JSON, takim jak

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

Ale widzę tylko stronę z wyświetlonymi danymi JSON, nie pobieram jej.

Przeszedłem przez kilka badań i ten twierdzi, że działa, ale nie widzę żadnej różnicy w moim kodzie.

Czy coś mi brakuje w kodzie?

Dziękuję za przeczytanie mojego pytania :)

Odpowiedzi:


257

Oto jak rozwiązałem to dla mojej aplikacji:

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

JS (czysty JS, nie jQuery tutaj):

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

W tym przypadku storageObjjest to obiekt js, który chcesz przechowywać, a „scena.json” to tylko przykładowa nazwa pliku wynikowego.

Takie podejście ma następujące zalety w porównaniu z innymi proponowanymi:

  • Żaden element HTML nie musi być klikany
  • Wynik zostanie nazwany tak, jak chcesz
  • nie jest potrzebne jQuery

Potrzebowałem tego zachowania bez wyraźnego klikania, ponieważ chcę automatycznie uruchomić pobieranie w pewnym momencie z js.

Rozwiązanie JS (bez 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
Jest to jedyne rozwiązanie, które będzie działać dla danych powyżej = ~ 2000 znaków. Ponieważ dodałeś dane:
— rjurney

1
Czy ktoś może wskazać mi specyfikację lub stronę MDN, która wyjaśnia bardziej szczegółowo, jak działa ta cała rzecz z dołączonym typem danych, tj. "data: text / json; charset = utf-8"? Używam tego, ale czuję się jak magia, wspaniale byłoby przeczytać szczegóły, ale nawet nie wiem, jak to znaleźć w Google.
— sidewinderguy

1
Nie działa to jednak w IE, gdy musisz pobrać duży plik zawierający ponad 2000 znaków.
— user388969

12
Nie będzie to jednak działać bez ograniczeń. Możesz pobrać tylko około 1 MB danych. Na przykład var storageObj = []; for (var i=0; i<1000000; ++i) storageObj.push('aaa');w przeglądarce Chrome 61
— oseiskar

1
Zamiast JSON.stringify(exportObj, null, 2)tego użyj @YASHDAVE
— TryingToImprove

40

Znalazłem odpowiedź.

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

wydaje mi się, że działa dobrze dla mnie.

** Wszystkie zasługi dla @ cowboy-ben-alman, który jest autorem powyższego kodu **


@ Cybear, czy możesz mi wyjaśnić trzecią linijkę?
— Rahul Khatri

Będziesz chciał dołączyć dane: do swojego adresu URL, w przeciwnym razie użytkownik prawdopodobnie przekroczy limit 2000 znaków w wielu przeglądarkach.
— rjurney

Hej, wiem, że to stara odpowiedź, ale wiem, że to rozwiązanie nie działa na IE (wszystkie z nich) IE nie zna odniesienia do atrybutu pobierania - link
— Ayalon Grinfeld

25

To byłaby czysta wersja JS (zaadaptowana z kowbojskiego):

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
Dziękuję za odpowiedź nawet po 2 latach, odkąd zadałem to pytanie! Wolę czysty JS od składni jQuery.
— Eugene Yu

Będziesz chciał dołączyć dane: do swojego adresu URL, w przeciwnym razie użytkownik prawdopodobnie przekroczy limit 2000 znaków w wielu przeglądarkach.
— rjurney

jak mogę rozpocząć pobieranie po załadowaniu strony. za każdym razem, gdy użytkownik przegląda adres URL strony, otrzymuje monit o pobranie
— user388969

1
Nie można pobrać dzisiejszego testu w Edge: data.json.
— Sarah Trees

25

Możesz spróbować użyć:

  • natywny konstruktor Blob interfejsu API JavaScript i
  • FileSaver.js saveAs() Sposób

Nie musisz w ogóle zajmować się żadnymi elementami 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);

Jeśli chcesz ładnie wydrukować JSON, zgodnie z tą odpowiedzią , możesz użyć:

JSON.stringify(data,undefined,2)

1
saveAs () pochodzi z FileSaver.js - github.com/eligrey/FileSaver.js
— Gautham

1
„W ogóle nie trzeba zajmować się żadnymi elementami HTML”… i czytając kod źródłowy filesaver.js… robi dokładnie to, co lol
— War,

1
Tak. Chciałem powiedzieć, że nie ma potrzeby zajmowania się bezpośrednio elementami HTML.
— Gautham

3
To najlepsza odpowiedź, ponieważ nie ma limitu rozmiaru 1 MB i używa biblioteki zamiast niestandardowych hacków
— oseiskar

głosował w górę na FileSaver ref. działa idealnie.
— Noone

15

Pracowały dla mnie:

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

a potem tak to nazwać

saveJSON(myJsonObject, "saved_data.json");

3
Chociaż jest to świetna odpowiedź, initMouseEvent()jest to przestarzały standard sieciowy i nie powinien być już używany. Zamiast tego użyj new MouseEvent()interfejsu. To tylko drobny refaktor.
— morkro

10

Niedawno musiałem utworzyć przycisk, który pobierałby plik json ze wszystkimi wartościami dużego formularza. Potrzebowałem tego do pracy z IE / Edge / Chrome. Oto co zrobiłem:

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

Wystąpił jeden problem z nazwą pliku i rozszerzeniem w Edge, ale w momencie pisania wydawało się, że jest to błąd w Edge, który ma zostać naprawiony.

Mam nadzieję, że to komuś pomoże


To działało w przeglądarce Chrome, ale wygląda na to, że nie działa w przeglądarce Firefox ... proszę o pomoc! codepen.io/anon/pen/ePYPJb
— Urmil Parikh

1
Niezła funkcja, dodaj, document.body.appendChild(a); a.style.display = 'none';aby działała w przeglądarce Firefox.
— Fabian von Ellerts

5

Proste, czyste rozwiązanie dla tych, którzy kierują reklamy tylko na nowoczesne przeglądarki:

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

Dzięki, tylko jeden, który nie spowodował problemów z rozmiarem
— Roelant

4

downloadNieruchomość linków jest nowy i nie jest obsługiwany w przeglądarce Internet Explorer (patrz tabela kompatybilności tutaj ). Aby znaleźć rozwiązanie tego problemu w różnych przeglądarkach, przyjrzyj się plikowi FileSaver.js


2

Reaguj : dodaj to w dowolnym miejscu w metodzie renderowania.

• Obiekt w stanie :

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

• Obiekt w rekwizytach :

<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 i style są opcjonalne, zmodyfikuj styl zgodnie ze swoimi potrzebami.


1

Spróbuj ustawić inny typ MIME: exportData = 'data:application/octet-stream;charset=utf-8,';

Ale mogą wystąpić problemy z nazwą pliku w oknie dialogowym zapisywania.


Przepraszam, że wróciłem późno. Wypróbowałem twoją odpowiedź i pobiera plik, ale zawiera błędne dane .. :(
— Eugene Yu

1
to zadziałało dla mnie ... data = "data:application/octet-stream;charset=utf-8," + encodeURIComponent(JSON.stringify(data)); window.open(data); po prostu pobiera plik jako „pobierz”, ale dane, które zostały zdefiniowane, a następnie zakodowane w formacie URI są takie, jakie powinny być.
— Jason Wiener

0

Jeśli wolisz fragment konsoli, raser niż nazwę pliku, możesz to zrobić:

window.open(URL.createObjectURL(
    new Blob([JSON.stringify(JSON)], {
      type: 'application/binary'}
    )
))
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.