Nazwa pliku blob JavaScript bez linku


189

Jak ustawić nazwę pliku blob w JavaScript podczas wymuszania pobierania go przez 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);
}

Uruchomienie powyższego kodu powoduje natychmiastowe pobranie pliku bez odświeżania strony, która wygląda następująco:

bfefe410-8d9c-4883-86c5-d76c50a24a1d

Zamiast tego chcę ustawić nazwę pliku jako my-download.json .

Odpowiedzi:


312

Jedyny sposób, w jaki jestem świadomy, to sztuczka używana przez FileSaver.js :

  1. Utwórz ukryty <a>tag.
  2. Ustaw jego hrefatrybut na adres URL obiektu blob.
  3. Ustaw jego downloadatrybut na nazwę pliku.
  4. Kliknij <a>znacznik.

Oto uproszczony przykład ( 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);

Napisałem ten przykład, aby zilustrować ten pomysł, zamiast tego w kodzie produkcyjnym użyj FileSaver.js.

Notatki

  • Starsze przeglądarki nie obsługują atrybutu „pobierz”, ponieważ jest to część HTML5.
  • Niektóre formaty plików są uważane przez przeglądarkę za niebezpieczne i pobieranie się nie udaje. Zapisywanie plików JSON z rozszerzeniem txt działa dla mnie.

2
@AshBlue Atrybut „pobierz” wymaga HTML5. Mój kod jest tylko przykładem, możesz także wypróbować stronę demonstracyjną FileSaver.js: eligrey.com/demos/FileSaver.js
— kol.

1
Co ciekawe, jeśli wielokrotnie próbujesz pobrać txt w ten sposób (naciskając wielokrotnie przycisk Uruchom na jsfiddle.net), pobieranie czasami kończy się niepowodzeniem.
— kol

2
Chciałem tylko wspomnieć, że to rozwiązanie nie będzie działać dla plików o rozmiarach większych niż określony próg. np.> 2 MB dla chrome. Rozmiar ten różni się w zależności od przeglądarki.
— manojadams

3
To nie działa dla mnie, ponieważ muszę otworzyć plik w nowej karcie. Muszę pokazać plik PDF w Chrome, ale muszę pokazać przyjazną nazwę użytkownika na pasku narzędzi URL, a jeśli użytkownik chce pobrać za pomocą ikony pobierania, muszę umieścić tę samą przyjazną nazwę w pliku.
— Adrian Paredes,

1
Wystarczy dodać, że nie trzeba tak naprawdę montować tagu na ciele, aby to zadziałało (wypróbowano teraz w Chrome)
— poza kodem

52

Chciałem tylko rozwinąć akceptowaną odpowiedź z obsługą Internet Explorera (w każdym razie najnowocześniejszych wersji) i uporządkować kod za pomocą 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();
}

Oto przykład Fiddle . Godspeed .


Działał idealnie.
— N8allan

1
Użyłem zaakceptowanego rozwiązania, ale nie zadziałało w Firefoksie! Nadal nie wiem dlaczego. Twoje rozwiązanie działało w Firefoksie. Dzięki.
— elahehab

@elahehab Moje rozwiązania zawsze działają;)
— Alexandru

27

Ta sama zasada co powyższe rozwiązania. Ale miałem problemy z Firefoksem 52.0 (32 bity), w którym duże pliki (> 40 MB) są obcinane w losowych pozycjach. Ponowne planowanie wywołania metody revokeObjectUrl () rozwiązuje ten problem.

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

przykład jsfiddle


1
Odkryłem, że ten hack setTimeout () naprawia MS Edge, w którym plik w ogóle się nie pobierał. Jednak tylko wywołanie revokeObjectURL () musi zostać opóźnione.
— Russell Phillips,

Przekonałem się, że „if (window.navigator.msSaveOrOpenBlob)” jest tym, co mi
— pomogło

23

Późno, ale ponieważ miałem ten sam problem, dodaję swoje rozwiązanie:

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
Dzięki @ben. To działa dobrze. Brak elementów dom, nic jak wyzwalanie jak zdarzenie kliknięcia. Po prostu działa świetnie z odpowiednim rozszerzeniem. Ale podana nazwa pliku nie jest brana pod uwagę, pobieranie „<object_url_id> .csv” zamiast „<myfileName> .csv”
— Ram Babu S

3
Wywołanie revokeObjectURLpo location.assigndziała poprawnie w przeglądarce Firefox, ale przerywa pobieranie w Chrome.
— Fred

Uwaga: „Edge nie obsługuje konstruktora plików”. Nr ref. caniuse.com/#feat=fileapi
— user1477388

To powinna być poprawna odpowiedź. Nie ma sensu tworzyć bezużytecznych obiektów w drzewie DOM
— Luiz Felipe

Teraz tak jest, od stycznia 20-20
— Luiz Felipe

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

czy jest jakiś sposób, aby otworzyć w nim nowe okno?
— Enrique Altuna

Myślę, że możesz zadzwonić link.click()zamiast wywołać zdarzenie myszy.
— Fred

2

Przykład roboczy działania przycisku pobierania, aby zapisać zdjęcie kota z adresu URL jako „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 nie działało dla mnie. pobiera dobrze, ale pobiera bez rozszerzenia pliku CSV na platformie Windows. Poniższe działało dla mnie.

    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

To jest moje rozwiązanie. Z mojego punktu widzenia nie można ominąć <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>

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.