Ім'я файлу JavaScript blob без посилання


189

Як встановити ім'я файлу blob у JavaScript під час примусового завантаження його через window.location?

function newFile(data) {
    var json = JSON.stringify(data);
    var blob = new Blob([json], {type: "octet/stream"});
    var url  = window.URL.createObjectURL(blob);
    window.location.assign(url);
}

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

bfefe410-8d9c-4883-86c5-d76c50a24a1d

Я хочу встановити ім'я файлу як my-download.json .

Відповіді:


312

Єдиний спосіб, про який я знаю, - це хитрість, яку використовує FileSaver.js :

  1. Створіть прихований <a>тег.
  2. Встановіть його hrefатрибут для URL-адреси блобу.
  3. Встановіть його downloadатрибут до імені файлу.
  4. Натисніть на <a>тег.

Ось спрощений приклад ( jsfiddle ):

var saveData = (function () {
    var a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
    return function (data, fileName) {
        var json = JSON.stringify(data),
            blob = new Blob([json], {type: "octet/stream"}),
            url = window.URL.createObjectURL(blob);
        a.href = url;
        a.download = fileName;
        a.click();
        window.URL.revokeObjectURL(url);
    };
}());

var data = { x: 42, s: "hello, world", d: new Date() },
    fileName = "my-download.json";

saveData(data, fileName);

Я написав цей приклад, щоб проілюструвати ідею, у виробничому коді замість цього використовуйте FileSaver.js.

Примітки

  • Старі браузери не підтримують атрибут "завантажити", оскільки він є частиною HTML5.
  • Деякі формати файлів браузер вважає незахищеними, а завантаження не вдається. Збереження файлів JSON з розширенням txt працює для мене.

2
@AshBlue Атрибут "завантажити" потребує HTML5. Мій код - лише приклад, ви також можете спробувати демонстраційну сторінку FileSaver.js
кол

1
Цікаво, що якщо ви неодноразово намагаєтеся скачати txt таким чином (натискаючи кнопку Запустити на jsfiddle.net знову і знову), завантаження іноді не вдається.
кол

2
Просто хотілося зазначити, що це рішення не працюватиме для файлів, розміри яких перевищують певний поріг. наприклад-> 2 Мб для хрому. Цей розмір залежить від браузера до браузера.
manojadams

3
Це не працює для мене, тому що мені потрібно відкрити файл на новій вкладці. Я маю показати PDF в Chrome, але мені потрібно вказати дружнє ім’я на панелі інструментів URL, і якщо користувач хоче завантажити через значок завантаження, я повинен вписати у файл таке ж дружнє ім’я.
Адріан Паредес

1
Просто додам, вам не потрібно насправді монтувати тег до корпусу, щоб це працювало (пробували зараз у Chrome)
поза кодом

52

Я просто хотів поширитись на прийняту відповідь із підтримкою Internet Explorer (у більшості сучасних версій, як би там не було), і виправити код за допомогою jQuery:

$(document).ready(function() {
    saveFile("Example.txt", "data:attachment/text", "Hello, world.");
});

function saveFile (name, type, data) {
    if (data !== null && navigator.msSaveBlob)
        return navigator.msSaveBlob(new Blob([data], { type: type }), name);
    var a = $("<a style='display: none;'/>");
    var url = window.URL.createObjectURL(new Blob([data], {type: type}));
    a.attr("href", url);
    a.attr("download", name);
    $("body").append(a);
    a[0].click();
    window.URL.revokeObjectURL(url);
    a.remove();
}

Ось приклад Фіддл . Godspeed .


Працювали чудово.
N8allan

1
Я використав прийняте рішення, але воно не працювало у firefox! Я досі не знаю, чому. Ваше рішення працювало в Firefox. Дякую.
elahehab

@elahehab Мої рішення завжди працюють;)
Олександру

27

Той самий принцип, як і рішення вище. Але у мене виникли проблеми з Firefox 52.0 (32 біт), де великі файли (> 40 Мбіт) усічені у випадкових місцях. Повторне планування виклику revokeObjectUrl () виправляє цю проблему.

function saveFile(blob, filename) {
  if (window.navigator.msSaveOrOpenBlob) {
    window.navigator.msSaveOrOpenBlob(blob, filename);
  } else {
    const a = document.createElement('a');
    document.body.appendChild(a);
    const url = window.URL.createObjectURL(blob);
    a.href = url;
    a.download = filename;
    a.click();
    setTimeout(() => {
      window.URL.revokeObjectURL(url);
      document.body.removeChild(a);
    }, 0)
  }
}

Приклад jsfiddle


1
Я виявив, що цей хакер setTimeout () виправляє MS Edge, де файл взагалі не завантажуватиметься. Однак лише заклик до revokeObjectURL () потрібно відкласти.
Рассел Філліпс

Я виявив, що "якщо (window.navigator.msSaveOrOpenBlob)" - це те, що зробив для мене трюк
Жак Олів'є

23

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

function newFile(data, fileName) {
    var json = JSON.stringify(data);
    //IE11 support
    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
        let blob = new Blob([json], {type: "application/json"});
        window.navigator.msSaveOrOpenBlob(blob, fileName);
    } else {// other browsers
        let file = new File([json], fileName, {type: "application/json"});
        let exportUrl = URL.createObjectURL(file);
        window.location.assign(exportUrl);
        URL.revokeObjectURL(exportUrl);
    }
}

5
Дякую @ben. Це добре працює. Ніяких елементів дому, нічого подібного до запуску подібної події клацання. Це просто чудово працює при правильному розширенні. Але вказане ім'я файлу не вважається, завантажуючи "<object_url_id> .csv" замість "<myfileName> .csv"
Ram Babu S

3
Виклик revokeObjectURLпісля location.assignроботи відмінно працює у Firefox, але порушує завантаження в Chrome.
Фред

Зауважте, що "Edge не підтримує конструктор файлів." Реф. caniuse.com/#feat=fileapi
user1477388

Це має бути правильна відповідь. Немає сенсу створювати непотрібні об’єкти на дереві DOM
Луїз Феліпе

Тепер так, з 20 січня
Луїз Феліпе

6
saveFileOnUserDevice = function(file){ // content: blob, name: string
        if(navigator.msSaveBlob){ // For ie and Edge
            return navigator.msSaveBlob(file.content, file.name);
        }
        else{
            let link = document.createElement('a');
            link.href = window.URL.createObjectURL(file.content);
            link.download = file.name;
            document.body.appendChild(link);
            link.dispatchEvent(new MouseEvent('click', {bubbles: true, cancelable: true, view: window}));
            link.remove();
            window.URL.revokeObjectURL(link.href);
        }
    }

чи є спосіб відкрити в ньому нове вікно?
Енріке Альтуна

Я думаю, ти можеш подзвонити link.click() замість того, щоб відправляти подію миші.
Фред

2

Робочий приклад кнопки завантаження, щоб зберегти фотографію кота з URL-адреси як "cat.jpg":

HTML:

<button onclick="downloadUrl('https://i.imgur.com/AD3MbBi.jpg', 'cat.jpg')">Download</button>

JavaScript:

function downloadUrl(url, filename) {
  let xhr = new XMLHttpRequest();
  xhr.open("GET", url, true);
  xhr.responseType = "blob";
  xhr.onload = function(e) {
    if (this.status == 200) {
      const blob = this.response;
      const a = document.createElement("a");
      document.body.appendChild(a);
      const blobUrl = window.URL.createObjectURL(blob);
      a.href = blobUrl;
      a.download = filename;
      a.click();
      setTimeout(() => {
        window.URL.revokeObjectURL(blobUrl);
        document.body.removeChild(a);
      }, 0);
    }
  };
  xhr.send();
}

1

window.location.assign не працював для мене. він завантажує чудово, але завантажує без розширення файл CSV на платформі Windows. Наступне працювало для мене.

    var blob = new Blob([csvString], { type: 'text/csv' });
    //window.location.assign(window.URL.createObjectURL(blob));
    var link = window.document.createElement('a');
    link.href = window.URL.createObjectURL(blob);
    // Construct filename dynamically and set to link.download
    link.download = link.href.split('/').pop() + '.' + extension; 
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);

0

Це моє рішення. З моєї точки зору, ви не можете обійти <a>.

function export2json() {
  const data = {
    a: '111',
    b: '222',
    c: '333'
  };
  const a = document.createElement("a");
  a.href = URL.createObjectURL(
    new Blob([JSON.stringify(data, null, 2)], {
      type: "application/json"
    })
  );
  a.setAttribute("download", "data.json");
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
}
<button onclick="export2json()">Export data to json file</button>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.