Завантажте об'єкт 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 (чистий JS, не jQuery тут):

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 символів даних. Тому що ви
попереджали

1
Чи може хтось вказати мені на сторінку специфікації або MDN, яка більш докладно пояснює, як працює вся ця передбачувана річ типу даних, тобто. "дані: text / json; charset = utf-8"? Я використовую це, але мені здається, що це магія, було б чудово прочитати деталі, але я навіть не знаю, як це зробити в Google.
sidewinderguy

1
Це не працює в IE, хоча вам доведеться завантажити великий файл з більш ніж 2000 символами.
користувач388969

12
Однак це не буде працювати без обмежень. Ви можете завантажити лише близько 1 МБ даних. Наприклад, 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 ви можете мені пояснити третій рядок?
Рахул Хатрі

Ви хочете додати дані: до вашої URL-адреси, інакше користувач може скористатися обмеженням до 2000 символів у багатьох браузерах.
rjurney

Гей, я знаю, що це стара відповідь, але знайте, це рішення не працює на 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 роки, оскільки я задав це питання! Я віддаю перевагу чистому JS над синтаксисом jQuery.
Євген Ю.

Ви хочете додати дані: до вашої URL-адреси, інакше користувач може скористатися обмеженням до 2000 символів у багатьох браузерах.
rjurney

як я можу змусити це завантаження розпочатись при завантаженні сторінки. щоразу, коли користувач переглядає URL-адресу сторінки, він отримує запит на завантаження
user388969

1
Сьогоднішній тест у Edge: data.json не вдалося завантажити.
Sarah Trees

25

Ви можете спробувати скористатися:

  • вбудований конструктор Blob API API та
  • 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 ... він робить саме це lol
Війна,

1
Так. Я мав на увазі сказати, що не потрібно безпосередньо спілкуватися з елементами HTML.
Гаутем

3
Це найкраща відповідь, оскільки вона не має обмеження в розмірі 1 Мб, і використовує бібліотеку замість користувацьких хакерів
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
Хоча це чудова відповідь, 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, яку слід виправити.

Сподіваюся, що це комусь допоможе


Це працювало на Chrome, але, здається, не працює на Firefox ... будь ласка, допоможіть! codepen.io/anon/pen/ePYPJb
Urmil Parikh

1
Приємна функція, додайте, document.body.appendChild(a); a.style.display = 'none';щоб вона працювала у Firefox.
Фабіан фон Еллертс

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

Дякую, лише один, який не
задав

4

downloadВластивість посилань є новим і не підтримується в Internet Explorer (дивіться таблицю сумісності тут ). Щоб вирішити цю проблему між браузером, я би поглянув на FileSaver.js


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 та стиль необов’язкові, змінюйте стиль відповідно до ваших потреб.


1

Спробуйте встановити інший тип MIME: exportData = 'data:application/octet-stream;charset=utf-8,';

Але в діалозі збереження можуть виникнути проблеми з іменем файлу.


Вибачте за те, що пізно повернулися до вас. Я спробував вашу відповідь, і він завантажує файл, але містить неправильні дані в ньому .. :(
Євген Ю.

1
це працювало для мене ... data = "data:application/octet-stream;charset=utf-8," + encodeURIComponent(JSON.stringify(data)); window.open(data); він просто завантажує файл як "скачати", але дані, які я закреслив, а потім зашифровано на uri, як слід.
Джейсон Вінер

0

Якщо ви віддаєте перевагу фрагменту консолі, raser, ніж ім'я файлу, ви можете зробити це:

window.open(URL.createObjectURL(
    new Blob([JSON.stringify(JSON)], {
      type: 'application/binary'}
    )
))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.