Загрузить объект 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


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)

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

Спасибо, единственное, что не доставляло мне проблем с размером
— вызвал у 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'}
    )
))

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 - имя файла, который вы хотите установить.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.