Esiste un modo per specificare un nome file suggerito quando si utilizzano i dati: URI?


225

Se ad esempio segui il link:

data:application/octet-stream;base64,SGVsbG8=

Il browser richiederà di scaricare un file costituito dai dati contenuti come base64 nel collegamento ipertestuale stesso. C'è un modo per suggerire un nome predefinito nel markup? In caso contrario, esiste una soluzione JavaScript?


forse non correlato a questo problema, ma suggerisco di utilizzare BLOB & URL.createObjectURL se questo non è un server o un vecchio ostacolo del browser
Endless

3
Alcuni browser supportano il parametro facoltativo "name" del mediatype:data:application/pdf;name=document.pdf;base64,BASE64_DATA_ENCODED
mems

Ho avuto il problema con Firefox pdf.js che in alcuni casi tende a bloccarsi se non riesce a estrarre un nome file dall'uri dati. vedi stackoverflow.com/questions/45585921/…
Bernhard

@mems Quali browser supportano il parametro "name"? Potete indicarmi una documentazione di riferimento? (il mio google-fu mi ha fallito).
TheAddonDepot

@DimuDesigns Almeno Firefox in quel momento. Sembra che non sia più il caso. È correlato al parametro "name" MIME Content-Type (! = Content-Disposition) (non in RFC?)
mems

Risposte:


158

Usa l' downloadattributo:

<a download='FileName' href='your_url'>

Esempio in diretta su html5-demos.appspot.com / ... .

Attualmente funziona su Chrome, Firefox, Edge, Opera e Safari desktop ma non iOS Safari o IE11.


3
@BioDesign: funziona anche con i dati: gli URI sono in Chrome. Vedi: jsfiddle.net/pYpqW
Senso

6
ma non puoi farlo window.location.replace. se ad esempio vuoi creare un dato: uri o uno generato da window.URL.createObjectURL, e scaricarlo come file, dovrai creare un <a> e fare clic su di esso: jsfiddle.net/flyingsheep/wpQtH (no, $(...).click()non funziona)
pecore volanti

1
Solo se tutti i browser fossero come Chrome ... [sospiro]
lampione

6
@flyingsheep $('<a href="data:text/plain,Test" download="test.txt">')[0].click()sembra funzionare bene qui (Chrome 23) (nota: ho usato il clickmetodo nativo , non quello di jQuery). Demo: jsfiddle.net/2zsRW
Rob W il

1
@flyingsheep sembra che stiano applicando una politica della stessa origine in Firefox "In Firefox 20 questo attributo è onorato solo per i collegamenti a risorse con la stessa origine". developer.mozilla.org/en-US/docs/Web/HTML/Element/a Nei miei test, Chrome non ha questa limitazione.
William Denniss,

62

Chrome lo rende molto semplice in questi giorni:

function saveContent(fileContents, fileName)
{
    var link = document.createElement('a');
    link.download = fileName;
    link.href = 'data:,' + fileContents;
    link.click();
}

Idk di cosa stanno parlando tutte queste altre risposte al primo tentativo su Chrome 30.
Michael J. Calkins,

2
Lo fa ora ma non è stato sempre così facile. Molte di queste risposte sono di anni fa. E funzionano anche per altri browser.
Holf,

7
Fare riferimento a http://caniuse.com/#feat=download per un elenco completo della compatibilità del browser.
Tixastronauta,

2
@tixastronauta: Nonostante le informazioni in quella pagina, non funziona nel mio Firefox 44. Funziona bene in Chrome. 48
Luis A. Florit,

Salve @Holf, c'è un modo anche per aggiungere il tipo di file o l'estensione o è semplice come speziarlo come il nome del file?
Fraccier,

51

Solo HTML: utilizzare l' downloadattributo:

<a download="logo.gif" href="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">Download transparent png</a>


Solo Javascript: puoi salvare qualsiasi URI di dati con questo codice:

function saveAs(uri, filename) {
  var link = document.createElement('a');
  if (typeof link.download === 'string') {
    link.href = uri;
    link.download = filename;

    //Firefox requires the link to be in the body
    document.body.appendChild(link);
    
    //simulate click
    link.click();

    //remove the link when done
    document.body.removeChild(link);
  } else {
    window.open(uri);
  }
}

var file = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
saveAs(file, 'logo.gif');

Chrome, Firefox e Edge 13+ utilizzeranno il nome file specificato.

IE11, Edge 12 e Safari 9 (che non supportano l' downloadattributo ) scaricheranno il file con il loro nome predefinito o lo visualizzeranno semplicemente in una nuova scheda, se è di un tipo di file supportato: immagini, video, file audio , ...


Entrambe le demo funzionano bene per me in Chrome 38 (ma dovrebbero funzionare in Chrome 14+)
fregante

Per una soluzione più completa, suggerisco di usare downloadjssu npm
fregante il

Funziona per me, ma la pagina del browser si aggiorna dopo. Mi chiedo come evitarlo?

1
Non funziona in cromo per le dimensioni del file> 2 MB a causa di restrizione da Chrome stackoverflow.com/questions/695151/...
Pranav Singh

Il limite appartiene data:all'URI, che è ciò che menziona la domanda. Questa risposta funziona anche con Blobs e qualsiasi altra cosa abbia un URI
fregante

40

Secondo RFC 2397 , no, non esiste.

Né ci sembra di essere qualsiasi attributo del <a>elemento che è possibile utilizzare.

Tuttavia HTML5 ha successivamente introdotto l' downloadattributo <a>sull'elemento, sebbene al momento della stesura il supporto non sia universale (nessun supporto MSIE, ad esempio)


9
la seconda frase era proprio al momento della scrittura, ma non lo è più . per ora, tuttavia, non è ancora ampiamente implementato.
pecora volante

vedi questo commento per maggiori informazioni :)
pecora volante

@flyingsheep, è ampiamente implementato.
Pacerier

1
non è stato 3 anni fa quando ho scritto quel commento
volo delle pecore il

Se il file è così lungo il download non riesce
deFreitas

21

Ho guardato un po 'nelle fonti di Firefox in netwerk / protocol / data / nsDataHandler.cpp

il gestore dati analizza solo contenuto / tipo e set di caratteri e osserva se nella stringa è presente "; base64"

rfc non specifica alcun nome file e almeno firefox non gestisce alcun nome file per esso, il codice genera un nome casuale più ".part"

Ho anche controllato il registro di Firefox

[b2e140]: DOCSHELL 6e5ae00 InternalLoad data:application/octet-stream;base64,SGVsbG8=
[b2e140]: Found extension '' (filename is '', handling attachment: 0)
[b2e140]: HelperAppService::DoContent: mime 'application/octet-stream', extension ''
[b2e140]: Getting mimeinfo from type 'application/octet-stream' ext ''
[b2e140]: Extension lookup on '' found: 0x0
[b2e140]: Ext. lookup for '' found 0x0
[b2e140]: OS gave back 0x43609a0 - found: 0
[b2e140]: Searched extras (by type), rv 0x80004005
[b2e140]: MIME Info Summary: Type 'application/octet-stream', Primary Ext ''
[b2e140]: Type/Ext lookup found 0x43609a0

file interessanti se vuoi guardare le fonti di mozilla:

data uri handler: netwerk/protocol/data/nsDataHandler.cpp
where mozilla decides the filename: uriloader/exthandler/nsExternalHelperAppService.cpp
InternalLoad string in the log: docshell/base/nsDocShell.cpp

Penso che tu possa smettere di cercare una soluzione per ora, perché sospetto che non ce ne sia :)

come notato in questo thread html5 ha downloadattributo, funziona anche su firefox 20 http://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#attr-hyperlink-download


3
Freddo! Anche se non sono necessariamente d'accordo sul fatto che Firefox sia la massima autorità su ciò che esiste. :)
Gleno,

14

Il seguente frammento di Javascript funziona in Chrome utilizzando il nuovo attributo "link" dei collegamenti e simulando un clic.

function downloadWithName(uri, name) {
  var link = document.createElement("a");
  link.download = name;
  link.href = uri;
  link.click();
}

E il seguente esempio mostra il suo utilizzo:

downloadWithName("data:,Hello%2C%20World!", "helloWorld.txt")

1
Questo non funziona in Firefox, ho aggiunto una risposta estesa di seguito con compatibilità Fx.
fregante,

12

No.

L'intero scopo è che si tratta di un flusso di dati, non di un file. L'origine dati non dovrebbe avere alcuna conoscenza del programma utente che lo gestisce come file ... e non lo è.


6
Lo scopo di data:è di fondere un blocco di dati interni in formato URL senza doverlo leggere da una fonte basata su protocollo. Il link nella risposta di @ silex mostra che la possibilità di suggerire un nome preferito per scriverlo è considerata utile, anche se non è ancora stata implementata.
Alnitak,

1
@Alnitak: utile? Assolutamente. Tecnicamente appropriato? Ancora non convinto. :)
Razze di leggerezza in orbita,

3
@Tomalak considera la differenza tra caricare i dati e salvarli - solo perché un blob è codificato in linea in un dato: URL non significa che non dovrebbe avere un nome preferito per salvarlo.
Alnitak,

4
Ma la tua frase sull'intero "scopo" è sbagliata. data:è stato appositamente inventato per consentire ai contenuti inline (piccoli) di apparire in un formato URL confuso in modo da poter essere utilizzati da elementi come tag immagine senza una richiesta HTTP separata. HTML afferma che il contenuto di un img srcattributo deve essere un URL, quindi è ciò che RFC 2397 ha creato. Non esiste "origine dati".
Alnitak,

6
@Alnitak: esattamente. Non esiste un'origine dati. Non c'è contesto. L'URI è i dati.
Razze di leggerezza in orbita

9

puoi aggiungere un attributo download all'elemento anchor.

campione:

<a download="abcd.cer"
    href="data:application/stream;base64,MIIDhTC......">down</a>

5

Guarda questo link: http://lists.w3.org/Archives/Public/uri/2010Feb/0069.html

Citazione:

Funziona anche (come in, non causa problemi) con; base64 alla fine in
questo modo (almeno in Opera):

Dati: text / plain; charset = utf-8; headers = Content-Disposition% 3A% 20attachment% 3B% 20filename% 3D% 22with% 20spaces.txt% 22% 0D% 0AContent-Lingua% 3A% 20IT; base64,4oiaDQo% 3D

Inoltre ci sono alcune informazioni negli altri messaggi della discussione.


sfortunatamente questo non viene scaricato.
James Khoury,

7
questa discussione era per un'estensione proposta al formato URI dei dati - non è stata implementata.
Alnitak,

Implementato o meno, con il supporto esistente per parametri arbitrari questo sarebbe un grande.
Dan Lugg,

5

Utilizzando i lavoratori dell'assistenza , questo è finalmente possibile nel vero senso della parola.

  1. Crea un URL falso. Ad esempio /saveAs/myPrettyName.jpg
  2. Usa URL in <a href, <img src, window.open (url), assolutamente tutto ciò che può essere fatto con un URL "reale".
  3. All'interno del lavoratore, cattura l'evento fetch e rispondi con i dati corretti.

Il browser ora suggerirà myPrettyName.jpg anche se l'utente apre il file in una nuova scheda e prova a salvarlo lì. Sarà esattamente come se il file provenisse dal server.

// In the service worker
self.addEventListener( 'fetch', function(e)
{
    if( e.request.url.startsWith( '/blobUri/' ) )
    {
        // Logic to select correct dataUri, and return it as a Response
        e.respondWith( dataURLAsRequest );
    }
});

1
Interessante! Per ora il supporto sembra essere piuttosto scarso
tuomassalo

C'è un modo per "rispondere" con un altro URL diretto a un file?
Iulian Onofrei,

4

C'è un piccolo script di soluzione alternativa su Google Code che ha funzionato per me:

http://code.google.com/p/download-data-uri/

Aggiunge un modulo con i dati in esso contenuti, lo invia e quindi lo rimuove nuovamente. Hacky, ma ha fatto il lavoro per me. Richiede jQuery.

Questa discussione è apparsa su Google prima della pagina del codice di Google e ho pensato che potesse essere utile avere anche il link qui.


Script interessante ma richiede che il server ottenga la risposta e la rispedisca, giusto? jsfiddle.net/hZySf
James Khoury,

Non sono sicuro da dove viene generato il file .. quel file viene archiviato nella codifica base64? (Non ho troppa familiarità con base64)
lampione

@streetlight: il "file" (ovvero i dati) è generato da Javascript. Il contesto di quel progetto (e probabilmente la maggior parte qui) presume che tu abbia un modo per ottenere i dati desiderati in una variabile JS. La differenza è che invece di presentarlo all'utente tramite un data:...URI, quello script crea un modulo per inviarlo al server. E quindi il server presumibilmente fa eco subito come una risposta di "download" HTTP (ovvero con un'intestazione Content-Disposition appropriata che specifica il nome file).
Andrzej Doyle,

4

Ecco una versione jQuery basata sulla versione di Holf e funziona con Chrome e Firefox mentre la sua versione sembra funzionare solo con Chrome. È un po 'strano aggiungere qualcosa al corpo per farlo, ma se qualcuno ha un'opzione migliore, sono tutto per questo.

var exportFileName = "export-" + filename;
$('<a></a>', {
    "download": exportFileName,
    "href": "data:," + JSON.stringify(exportData, null,5),
    "id": "exportDataID"
}).appendTo("body")[0].click().remove();

1
Con jQuery 1.11 ottengo un'eccezione a causa di .remove (). Ho $().appendTo()variable.click(); variable.remove()
risolto il

@ p0lar_bear dovresti ottenere quell'eccezione con qualsiasi jQuery, perché ottenere [0]da qualsiasi "elemento jQuery" dovrebbe restituire il primo elemento DOM che rappresenta, che essenzialmente "ti porta fuori da" jQuery.
drzaus,

In realtà, non dovrebbe essere necessario per aggiungere / rimuovere l'elemento a tutti - vedere i commenti a stackoverflow.com/a/17311705/1037948
drzaus

3

È un po 'hacker, ma prima mi sono trovato nella stessa situazione. Stavo generando dinamicamente un file di testo in javascript e volevo fornirlo per il download codificandolo con l'URI dei dati.

Ciò è possibile con un minore intervento da parte dell'utente. Genera un collegamento<a href="data:...">right-click me and select "Save Link As..." and save as "example.txt"</a> . Come ho già detto, questo non è elegante, ma funziona se non hai bisogno di una soluzione professionale.

Ciò potrebbe essere meno doloroso utilizzando Flash per copiare prima il nome negli Appunti. Naturalmente se ti lasci usare Flash o Java (ora con sempre meno supporto per il browser penso?), Probabilmente potresti trovare un altro modo per farlo.


Questa non è una soluzione e non soddisfa ciò che è stato chiesto. Scusate.
jcolebrand,

7
Lol @ "intervento dell'utente minore". Far sì che l'utente faccia tutto per te non è un "intervento dell'utente minore".
Razze di leggerezza in orbita,

Combina questo con stackoverflow.com/questions/17311645/… per attivare il link generato e non è necessario l'intervento dell'utente. È possibile specificare l' attributo HTML5download per suggerire un nome come indicato da molte altre risposte .
drzaus,

Questa è un'ottima soluzione per Safari. Usa Modernizr per rilevare quando l'attributo di download non è supportato e aggiorna il testo del link!
littledynamo,

2

Questo funziona con Firefox 43.0 (vecchio non testato):

dl.js:

function download() {
  var msg="Hello world!";
  var blob = new File([msg], "hello.bin", {"type": "application/octet-stream"});

  var a = document.createElement("a");
  a.href = URL.createObjectURL(blob);

  window.location.href=a;
}

dl.html

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">

<head>
    <meta charset="utf-8"/>
    <title>Test</title>
    <script type="text/javascript" src="dl.js"></script>
</head>

<body>
<button id="create" type="button" onclick="download();">Download</button>
</body>
</html>

Se si fa clic sul pulsante, viene offerto un file chiamato hello.bin per il download. Il trucco è usare File invece di BLOB .

riferimento: https://developer.mozilla.org/de/docs/Web/API/File


0
var isIE = /*@cc_on!@*/false || !!document.documentMode; // At least IE6
var sessionId ='\n';
var token = '\n';
var caseId = CaseIDNumber + '\n';
var url = casewebUrl+'\n';
var uri = sessionId + token + caseId + url;//data in file
var fileName = "file.i4cvf";// any file name with any extension
if (isIE)
    {
            var fileData = ['\ufeff' + uri];
            var blobObject = new Blob(fileData);
            window.navigator.msSaveOrOpenBlob(blobObject, fileName);
    }
    else //chrome
    {
        window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
         window.requestFileSystem(window.TEMPORARY, 1024 * 1024, function (fs) {
            fs.root.getFile(fileName, { create: true }, function (fileEntry) { 
                fileEntry.createWriter(function (fileWriter) {
                    var fileData = ['\ufeff' + uri];
                    var blob = new Blob(fileData);
                    fileWriter.addEventListener("writeend", function () {
                        var fileUrl = fileEntry.toURL();
                        var link = document.createElement('a');
                        link.href = fileUrl;
                        link.download = fileName;
                        document.body.appendChild(link);
                        link.click();
                        document.body.removeChild(link);
                    }, false);
                    fileWriter.write(blob);
                }, function () { });
            }, function () { });
         }, function () { });
    }

1
per favore aggiungi una spiegazione più dettagliata alla tua risposta - stackoverflow.com/help/how-to-answer
Sebastian Brosch

1
questa risposta è spazzatura
Jonathan Taylor,

-2

In realtà puoi farlo, in Chrome e FireFox.

Prova il seguente URL, scaricherà il codice che è stato utilizzato.

data:text/html;base64,PGEgaHJlZj0iZGF0YTp0ZXh0L2h0bWw7YmFzZTY0LFBHRWdhSEpsWmowaVVGVlVYMFJCVkVGZlZWSkpYMGhGVWtVaUlHUnZkMjVzYjJGa1BTSjBaWE4wTG1oMGJXd2lQZ284YzJOeWFYQjBQZ3BrYjJOMWJXVnVkQzV4ZFdWeWVWTmxiR1ZqZEc5eUtDZGhKeWt1WTJ4cFkyc29LVHNLUEM5elkzSnBjSFErIiBkb3dubG9hZD0idGVzdC5odG1sIj4KPHNjcmlwdD4KZG9jdW1lbnQucXVlcnlTZWxlY3RvcignYScpLmNsaWNrKCk7Cjwvc2NyaXB0Pg==
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.