Загрузить объект JSON в виде файла из браузера

154

У меня есть следующий код, позволяющий пользователям загружать строки данных в файл 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, а не загружаю ее.

Я провел некоторое исследование, и этот утверждает, что работает, но я не вижу никакой разницы в своем коде.

Мне что-то не хватает в моем коде?

Спасибо, что прочитали мой вопрос :)

Евгений Ю
источник

Ответы:

279

Вот как я решил это для своего приложения:

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 символов данных. Потому что вы добавили данные:
rjurney 01
1
Может ли кто-нибудь указать мне на спецификацию или страницу MDN, которая более подробно объясняет, как работает вся эта вещь с добавленными типами данных, т.е. "данные: текст / json; charset = utf-8"? Я использую это, но это похоже на волшебство, было бы здорово прочитать подробности, но я даже не знаю, как это сделать в Google.
sidewinderguy
1
Это не работает в IE, когда вам нужно загрузить большой файл, содержащий более 2000 символов.
user388969
12
Однако это не будет работать без ограничений. Вы можете загрузить не более 1 МБ данных. Например, var storageObj = []; for (var i=0; i<1000000; ++i) storageObj.push('aaa');выдает сообщение «Ошибка загрузки - ошибка сети» в Chrome 61
oseiskar 01
2
@YASHDAVE используйте JSON.stringify(exportObj, null, 2)вместо этого
TryingToImprove
42

Нашел ответ.

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, можешь мне объяснить третью строчку?
Рахул Хатри
Вы захотите добавить data: к своему URL-адресу, иначе пользователь, скорее всего, достигнет ограничения в 2000 символов во многих браузерах.
rjurney 01
Привет, я знаю, что это старый ответ, но знаю, что это решение не работает в IE (всех из них) IE не знаком со ссылкой на атрибут загрузки - ссылка
Аялон Гринфельд
27

Это будет чистая версия 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

jbcdefg
источник
3
Спасибо за ответ, даже если прошло 2 года с тех пор, как я задал этот вопрос! Я предпочитаю чистый JS синтаксису jQuery.
Юджин Ю
Вы захотите добавить data: к своему URL-адресу, иначе пользователь, скорее всего, достигнет ограничения в 2000 символов во многих браузерах.
rjurney 01
как я могу начать загрузку при загрузке страницы. всякий раз, когда пользователь просматривает URL-адрес страницы, он получает запрос на загрузку
user388969
1
Сегодняшний тест в Edge: не удалось загрузить data.json.
Sarah Trees
27

Вы можете попробовать использовать:

  • конструктор Blob встроенного API JavaScript и
  • 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)
Gautham
источник
2
SaveAs () составляет от FileSaver.js - github.com/eligrey/FileSaver.js
Gautham
1
«Нет необходимости иметь дело с какими-либо элементами HTML» ... и чтение исходного кода filesaver.js ... это именно то, лол
War
1
Да уж. Я хотел сказать, что нет необходимости иметь дело с элементами HTML напрямую.
Gautham
3
Это лучший ответ, поскольку он не имеет ограничения на размер
oseiskar 01
проголосовали за FileSaver ref. работает отлично.
Нет
17

Для меня сработало следующее:

/* 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
11

Недавно мне пришлось создать кнопку, которая загружала бы файл 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, но на момент написания это казалось ошибкой Edge, которая должна быть исправлена.

Надеюсь, это кому-то поможет

Брэд
источник
Это сработало в Chrome, но, похоже, не работает в Firefox ... пожалуйста, помогите! codepen.io/anon/pen/ePYPJb
Урмил Парих
1
Хорошая функция, добавьте, document.body.appendChild(a); a.style.display = 'none';чтобы она работала в Firefox.
Fabian von Ellerts
8

Простое и понятное решение для тех, кто ориентирован только на современные браузеры:

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');
пользователь993683
источник
Спасибо, единственное, что не доставляло мне проблем с размером
вызвал у Roelant
5

В downloadСвойство ссылок является новым и не поддерживается в Internet Explorer (смотрите таблицу совместимости здесь ). Для кросс-браузерного решения этой проблемы я бы взглянул на FileSaver.js

Робертжд
источник
2

Реагировать : добавьте это куда хотите в методе рендеринга.

• Объект в состоянии :

<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, как и должно быть.
Джейсон Винер
0

Если вы предпочитаете фрагмент консоли, raser, а не имя файла, вы можете сделать это:

window.open(URL.createObjectURL(
    new Blob([JSON.stringify(JSON)], {
      type: 'application/binary'}
    )
))
zb '
источник
0
    downloadJsonFile(data, filename: string){
        // Creating a blob object from non-blob data using the Blob constructor
        const blob = new Blob([JSON.stringify(data)], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        // Create a new anchor element
        const a = document.createElement('a');
        a.href = url;
        a.download = filename || 'download';
        a.click();
        a.remove();
      }

Вы можете легко автоматически загрузить файл с помощью Blob и передать его в первом параметре downloadJsonFile. filename - имя файла, который вы хотите установить.

Нам До
источник