Nome file BLOB JavaScript senza collegamento


189

Come si imposta il nome di un file BLOB in JavaScript quando si forza il download attraverso 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);
}

L'esecuzione del codice precedente scarica immediatamente un file senza un aggiornamento della pagina simile a:

bfefe410-8d9c-4883-86c5-d76c50a24a1d

Voglio invece impostare il nome file come my-download.json .

Risposte:


313

L'unico modo di cui sono a conoscenza è il trucco usato da FileSaver.js :

  1. Crea un <a>tag nascosto .
  2. Impostare il suo hrefattributo sull'URL del BLOB.
  3. Imposta il suo downloadattributo sul nome del file.
  4. Fai clic sul <a>tag.

Ecco un esempio semplificato ( 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);

Ho scritto questo esempio solo per illustrare l'idea, nel codice di produzione utilizzare invece FileSaver.js.

Appunti

  • I browser meno recenti non supportano l'attributo "download", poiché fa parte di HTML5.
  • Alcuni formati di file sono considerati non sicuri dal browser e il download non riesce. Il salvataggio di file JSON con estensione txt funziona per me.

2
@AshBlue L'attributo "download" richiede HTML5. Il mio codice è solo un esempio, puoi anche provare la pagina demo di FileSaver.js: idoneo.com/demos/FileSaver.js
kol

1
È interessante notare che se si tenta ripetutamente di scaricare un txt in questo modo (premendo il pulsante Esegui su jsfiddle.net ancora e ancora), il download a volte non riesce.
kol

2
Volevo solo ricordare che questa soluzione non funzionerà per file con dimensioni superiori a una determinata soglia. ad es.> 2 MB per Chrome. Questa dimensione varia da browser a browser.
manojadams,

3
Questo non funziona per me perché devo aprire il file in una nuova scheda. Devo mostrare un PDF in Chrome, ma devo mostrare un nome intuitivo nella barra degli strumenti dell'URL e se l'utente desidera scaricare tramite l'icona di download, devo inserire lo stesso nome descrittivo nel file.
Adrian Paredes,

1
Solo per aggiungere, non è necessario montare effettivamente un tag sul corpo per farlo funzionare (provato proprio ora in Chrome)
oltre il codice

52

Volevo solo espandere la risposta accettata con il supporto per Internet Explorer (la maggior parte delle versioni moderne, comunque) e riordinare il codice usando 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();
}

Ecco un esempio di violino . Godspeed .


Ha funzionato perfettamente.
N8allan,

1
Ho usato la soluzione accettata ma non ha funzionato su Firefox! Ancora non so perché. La tua soluzione ha funzionato in Firefox. Grazie.
elahehab,

@elahehab Le mie soluzioni funzionano sempre;)
Alexandru

27

Stesso principio delle soluzioni sopra. Ma ho avuto problemi con Firefox 52.0 (32 bit) in cui i file di grandi dimensioni (> 40 MByte) vengono troncati in posizioni casuali. La riprogrammazione della chiamata di revokeObjectUrl () risolve questo problema.

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

esempio jsfiddle


1
Ho scoperto che questo hack setTimeout () risolve MS Edge, dove il file non si scarica affatto. Tuttavia, solo la chiamata a revokeObjectURL () deve essere ritardata.
Russell Phillips,

Ho scoperto che "if (window.navigator.msSaveOrOpenBlob)" è quello che ha fatto il trucco per me
Jacques Olivier,

23

In ritardo, ma poiché ho avuto lo stesso problema, aggiungo la mia soluzione:

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
Grazie @ben. Funziona benissimo. Nessun elemento dom, niente di simile da attivare come evento click. Funziona alla grande con l'estensione corretta. Ma il nome file specificato non viene preso in considerazione, scaricando "<object_url_id> .csv" invece di "<myfileName> .csv"
Ram Babu S

3
Chiamare revokeObjectURLdopo location.assignfunziona bene in Firefox, ma interrompe il download su Chrome.
Fred

Si noti che "Edge non supporta il costruttore di file". Ref. caniuse.com/#feat=fileapi
user1477388

Questa dovrebbe essere la risposta corretta. Inutile creare oggetti inutili nella struttura DOM
Luiz Felipe,

Ora lo fa, dal gennaio '20
Luiz Felipe il

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

c'è un modo per aprire al suo interno una nuova finestra?
Enrique Altuna,

Penso che puoi chiamare link.click()invece di inviare un evento del mouse.
Fred

2

Esempio funzionante di un pulsante di download, per salvare una foto di un gatto da un URL come "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 non ha funzionato per me. scarica bene ma scarica senza estensione per un file CSV su piattaforma Windows. Quanto segue ha funzionato per me.

    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

Questa è la mia soluzione Dal mio punto di vista, non puoi bypassare il <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>

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.