Apakah ada cara untuk menentukan nama file yang disarankan saat menggunakan data: URI?

225

Jika misalnya Anda mengikuti tautan:

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

Browser akan meminta Anda untuk mengunduh file yang terdiri dari data yang disimpan sebagai base64 di hyperlink itu sendiri. Apakah ada cara untuk menyarankan nama default di markup? Jika tidak, apakah ada solusi JavaScript?

tepang
sumber
mungkin tidak terkait dengan masalah ini, tetapi saya sarankan menggunakan blob's & URL.createObjectURL jika ini bukan hambatan server atau browser lama
Tak Berujung
3
Beberapa browser mendukung parameter "nama" parameter mediatype:data:application/pdf;name=document.pdf;base64,BASE64_DATA_ENCODED
mems
Saya punya masalah dengan Firefox pdf.js yang cenderung menggantung dalam beberapa kasus jika tidak dapat mengekstrak nama file dari data uri. lihat stackoverflow.com/questions/45585921/…
Bernhard
@mems Peramban mana yang mendukung parameter "nama"? Bisakah Anda mengarahkan saya ke beberapa dokumentasi referensi? (Google-fu saya telah mengecewakan saya).
TheAddonDepot
@DimuDesigns Setidaknya Firefox saat itu. Sepertinya tidak lagi seperti itu. Ini terkait dengan MIME Content-Type (! = Content-Disposition) "name" parameter (not in RFC?)
mems

Jawaban:

158

Gunakan downloadatribut:

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

Hidup misalnya pada html5-demos.appspot.com / ... .

Saat ini berfungsi pada Chrome, Firefox, Edge, Opera, dan desktop Safari tetapi tidak untuk iOS Safari atau IE11.

Dan Fabulich
sumber
3
@BioDesign: Ini berfungsi bahkan dengan data: URI di chrome. Lihat: jsfiddle.net/pYpqW
Senseful
6
tetapi Anda tidak dapat melakukannya dengan window.location.replace. jika Anda ingin membuat data: uri atau yang dihasilkan oleh window.URL.createObjectURL, dan mengunduhnya sebagai file, Anda harus membuat <a> dan mengkliknya: jsfiddle.net/flyingsheep/wpQtH (tidak, $(...).click()tidak berfungsi)
domba terbang
1
Hanya jika semua peramban seperti Chrome ... [sigh]
streetlight
6
@flyingsheep $('<a href="data:text/plain,Test" download="test.txt">')[0].click()tampaknya berfungsi dengan baik di sini (Chrome 23) (catatan: Saya menggunakan clickmetode asli , bukan jQuery's). Demo: jsfiddle.net/2zsRW
Rob W
1
@flyingsheep tampaknya mereka memberlakukan kebijakan asal yang sama di Firefox "Di Firefox 20 atribut ini hanya dihormati untuk tautan ke sumber daya dengan asal yang sama." developer.mozilla.org/en-US/docs/Web/HTML/Element/a Dalam pengujian saya, Chrome tidak memiliki batasan ini.
William Denniss
62

Chrome membuat ini sangat sederhana hari ini:

function saveContent(fileContents, fileName)
{
    var link = document.createElement('a');
    link.download = fileName;
    link.href = 'data:,' + fileContents;
    link.click();
}
Serigala
sumber
Idk apa semua jawaban lain yang dibicarakan tentang ini berfungsi pada percobaan pertama di Chrome 30.
Michael J. Calkins
2
Memang sekarang tapi itu tidak selalu mudah. Banyak dari jawaban ini berasal dari tahun lalu. Dan mereka juga berfungsi untuk browser lain.
Holf
7
Rujuk ke http://caniuse.com/#feat=download untuk daftar lengkap kompatibilitas browser.
tixastronauta
2
@tixastronauta: Meskipun ada info di halaman itu, tidak berfungsi di firefox saya 44. Bekerja dengan baik di Chrome. 48
Luis A. Florit
Hai @Holf ada cara juga untuk menambahkan jenis file atau ekstensi atau hanya sesederhana spceficy sebagai nama file?
Fraccier
51

Hanya HTML: gunakan downloadatribut:

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


Hanya Javascript: Anda dapat menyimpan data URI apa pun dengan kode ini:

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, dan Edge 13+ akan menggunakan nama file yang ditentukan.

IE11, Edge 12, dan Safari 9 (yang tidak mendukung downloadatribut ) akan mengunduh file dengan nama default mereka atau mereka hanya akan menampilkannya di tab baru, jika itu jenis file yang didukung: gambar, video, file audio , ...

fregante
sumber
Kedua demo berfungsi dengan baik untuk saya di Chrome 38 (tetapi harus bekerja di Chrome
14+
Untuk solusi yang lebih lengkap, saya sarankan menggunakan downloadjspada npm
fregante
Ini berfungsi untuk saya tetapi halaman browser di-refresh setelah itu. Bertanya-tanya bagaimana cara mencegahnya?
1
Tidak bekerja di chrome untuk ukuran file> 2MB karena pembatasan oleh chrome stackoverflow.com/questions/695151/…
Pranav Singh
Batasnya adalah milik data:URI, yang disebut oleh pertanyaan itu. Jawaban ini juga bekerja dengan Blobs dan apa pun yang memiliki URI
fregante
40

Menurut RFC 2397 , tidak, tidak ada.

Ada juga tidak muncul untuk menjadi setiap atribut dari <a>elemen yang Anda dapat menggunakan salah.

Namun HTML5 kemudian memperkenalkan downloadatribut pada <a>elemen, meskipun pada saat penulisan dukungan tidak universal (tidak ada dukungan MSIE, misalnya)

Alnitak
sumber
9
kalimat kedua tepat pada saat penulisan, tetapi sekarang tidak lagi . sampai sekarang, belum diimplementasikan secara luas.
domba terbang
lihat komentar ini untuk info lebih lanjut :)
flying sheep
@flyingsheep, Hal ini secara luas diterapkan.
Pacerier
1
itu bukan 3 tahun yang lalu ketika saya menulis komentar itu
domba terbang
Jika file terlalu lama unduhan gagal
deFreitas
21

Saya telah melihat sedikit sumber firefox di netwerk / protokol / data / nsDataHandler.cpp

pengendali data hanya mem-parsing konten / tipe dan charset, dan terlihat jika ada "; base64" di dalam string

rfc tidak menentukan nama file dan setidaknya firefox tidak menangani nama file untuk itu, kode menghasilkan nama acak ditambah ".part"

Saya juga sudah memeriksa log 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 yang menarik jika Anda ingin melihat sumber 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

Saya pikir Anda dapat berhenti mencari solusi untuk saat ini, karena saya curiga tidak ada :)

seperti yang terlihat di utas ini html5 memiliki downloadatribut, ia bekerja juga di firefox 20 http://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#attr-hyperlink-download

sherpya
sumber
3
Keren! Meskipun saya tidak selalu setuju bahwa Firefox adalah otoritas tertinggi atas apa yang ada. :)
Gleno
14

Cuplikan Javascript berikut berfungsi di Chrome dengan menggunakan atribut tautan 'unduh' baru dan mensimulasikan klik.

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

Dan contoh berikut menunjukkan penggunaannya:

downloadWithName("data:,Hello%2C%20World!", "helloWorld.txt")
burung hantu
sumber
1
Ini tidak berfungsi di Firefox, saya menambahkan jawaban yang diperluas di bawah ini dengan kompatibilitas Fx.
fregante
12

Tidak.

Seluruh tujuannya adalah bahwa ini adalah datastream, bukan file. Sumber data seharusnya tidak memiliki pengetahuan tentang agen pengguna yang menanganinya sebagai file ... dan tidak.

Lightness Races di Orbit
sumber
6
Tujuannya data:adalah untuk memalsukan blok data internal ke dalam format URL tanpa harus membacanya dari sumber berbasis protokol. Tautan dalam jawaban @ silex menunjukkan bahwa kemampuan untuk menyarankan nama yang disukai untuk menuliskannya dianggap bermanfaat, bahkan jika belum diimplementasikan.
Alnitak
1
@Alnitak: Berguna? Benar. Tepat secara teknis? Masih belum yakin. :)
Lightness Races in Orbit
3
@Tomalak mempertimbangkan perbedaan antara memuat data dan menyimpannya - hanya karena gumpalan disandikan sebaris dalam data: URL tidak berarti bahwa ia tidak boleh memiliki nama yang disukai untuk menyimpannya.
Alnitak
4
Tapi kalimat Anda tentang "seluruh tujuan" itu salah. data:secara khusus diciptakan untuk memungkinkan (kecil) konten inline untuk muncul dalam format URL yang dikaburkan sehingga dapat digunakan oleh hal-hal seperti tag gambar tanpa permintaan HTTP terpisah. HTML mengatakan konten img srcatribut harus berupa URL, jadi itulah yang dibuat RFC 2397. Tidak ada "sumber data".
Alnitak
6
@Alnitak: Tepat. Tidak ada sumber data. Tidak ada konteks. URI adalah datanya.
Lightness Races in Orbit
9

Anda dapat menambahkan atribut unduhan ke elemen jangkar.

Sampel:

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

Lihatlah tautan ini: http://lists.w3.org/Archives/Public/uri/2010Feb/0069.html

Mengutip:

Ia bahkan berfungsi (seperti pada, tidak menyebabkan masalah) dengan; base64 di akhir
seperti ini (setidaknya di Opera):

data: teks / polos; charset = utf-8; header = Konten-Disposisi% 3A% 20attachment% 3B% 20filename% 3D% 22dengan% 20spaces.txt% 22% 0D% 0Konten-Bahasa% 3A% 20en; base64,4oiaDQo% 3D

Juga ada beberapa info dalam pesan-pesan sisa diskusi.

silex
sumber
sayangnya ini tidak bisa diunduh.
James Khoury
7
diskusi ini adalah untuk ekstensi yang diusulkan ke format data URI - belum diterapkan.
Alnitak
Diterapkan atau tidak, dengan dukungan yang ada untuk parameter sewenang-wenang ini akan menjadi besar.
Dan Lugg
5

Menggunakan pekerja layanan , ini akhirnya mungkin dalam arti yang sebenarnya.

  1. Buat URL palsu. Misalnya /saveAs/myPrettyName.jpg
  2. Gunakan URL di <a href, <img src, window.open (url), benar-benar segala sesuatu yang dapat dilakukan dengan URL "nyata".
  3. Di dalam pekerja, tangkap acara pengambilan, dan tanggapi dengan data yang benar.

Browser sekarang akan menyarankan myPrettyName.jpg bahkan jika pengguna membuka file di tab baru, dan mencoba untuk menyimpannya di sana. Ini akan persis seperti jika file itu berasal dari 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 );
    }
});
Adria
sumber
1
Menarik! Dukungan tampaknya cukup dangkal untuk saat ini, meskipun: caniuse.com/#feat=serviceworkers
tuomassalo
Apakah ada cara untuk "merespons" dengan url langsung lain ke file?
Iulian Onofrei
4

Ada skrip solusi kecil di Google Code yang berfungsi untuk saya:

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

Itu menambahkan formulir dengan data di dalamnya, mengirimkannya dan kemudian menghapus formulir itu lagi. Meretas, tetapi itu berhasil bagi saya. Membutuhkan jQuery.

Utas ini muncul di Google sebelum laman Kode Google dan saya pikir mungkin ada gunanya memiliki tautan di sini juga.

Fabian B.
sumber
Script yang menarik tetapi memang membutuhkan server untuk mendapatkan respons dan mengirimnya kembali kan? jsfiddle.net/hZySf
James Khoury
Saya tidak yakin dari mana file itu dihasilkan .. apakah file itu disimpan dalam encode base64? (Saya tidak terlalu terbiasa dengan base64)
lampu jalan
@streetlight: "file" (yaitu data) dihasilkan oleh Javascript. Konteks proyek itu (dan mungkin sebagian besar di sini) mengasumsikan bahwa Anda memiliki beberapa cara untuk memasukkan data yang Anda inginkan ke dalam variabel JS. Perbedaannya adalah bahwa alih-alih menampilkannya kepada pengguna melalui data:...URI, skrip itu membuat formulir untuk POST ke server. Dan server kemudian mungkin menggemakannya langsung sebagai respons "unduh" HTTP (yaitu dengan header Content-Disposition yang sesuai menentukan nama file).
Andrzej Doyle
4

Ini adalah versi jQuery yang didasarkan pada versi Holf dan bekerja dengan Chrome dan Firefox sedangkan versinya tampaknya hanya berfungsi dengan Chrome. Agak aneh menambahkan sesuatu ke tubuh untuk melakukan ini, tetapi jika seseorang memiliki pilihan yang lebih baik saya akan melakukannya.

var exportFileName = "export-" + filename;
$('<a></a>', {
    "download": exportFileName,
    "href": "data:," + JSON.stringify(exportData, null,5),
    "id": "exportDataID"
}).appendTo("body")[0].click().remove();
kgividen
sumber
1
Dengan jQuery 1.11 saya mendapatkan pengecualian karena .remove (). Saya menyiasati hal ini dengan menugaskan $().appendTo()ke variabel lalu memanggilvariable.click(); variable.remove()
p0lar_bear
@ p0lar_bear Anda harus mendapatkan pengecualian itu dengan jQuery apa pun, karena mendapatkan [0]dari "elemen jQuery" apa pun harus mengembalikan elemen DOM pertama yang diwakilinya, yang pada dasarnya "membawa Anda keluar dari" jQuery.
drzaus
Anda sebenarnya tidak perlu menambahkan / menghapus elemen sama sekali - lihat komentar di stackoverflow.com/a/17311705/1037948
drzaus
3

Ini semacam peretasan, tapi saya pernah mengalami situasi yang sama sebelumnya. Saya secara dinamis menghasilkan file teks dalam javascript dan ingin menyediakannya untuk diunduh dengan menyandikannya dengan data-URI.

Ini dimungkinkan dengan intervensi pengguna utama minor . Buat tautan <a href="data:...">right-click me and select "Save Link As..." and save as "example.txt"</a>. Seperti yang saya katakan, ini tidak elegan, tetapi berfungsi jika Anda tidak memerlukan solusi profesional.

Ini bisa dibuat lebih tidak menyakitkan dengan menggunakan flash untuk menyalin nama ke clipboard terlebih dahulu. Tentu saja jika Anda membiarkan diri Anda menggunakan Flash atau Java (sekarang dengan dukungan browser yang semakin sedikit, saya kira?), Anda mungkin bisa menemukan cara lain untuk melakukan ini.

ninjagecko
sumber
Ini bukan solusi dan tidak memenuhi apa yang diminta. Maaf.
jcolebrand
7
Lol @ "intervensi pengguna kecil". Membuat pengguna melakukan semuanya untuk Anda bukanlah "intervensi pengguna kecil".
Lightness Races in Orbit
Gabungkan ini dengan stackoverflow.com/questions/17311645/… untuk memicu tautan yang dibuat dan Anda tidak memerlukan intervensi pengguna. Anda dapat menentukan atribut HTML5download untuk menyarankan nama seperti yang disebutkan oleh banyak jawaban lain .
drzaus
Ini adalah solusi yang bagus untuk Safari. Gunakan Modernizr untuk mendeteksi ketika atribut unduhan tidak didukung dan perbarui teks tautan!
littledynamo
2

Ini berfungsi dengan Firefox 43.0 (lebih tua tidak diuji):

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>

Jika tombol diklik maka ditawarkan file bernama hello.bin untuk diunduh. Triknya adalah menggunakan File alih-alih Blob .

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

NeutronenStern
sumber
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 () { });
    }
Sushama Pradhan
sumber
1
tolong tambahkan penjelasan yang lebih terperinci untuk jawaban Anda - stackoverflow.com/help/how-to-answer
Sebastian Brosch
1
jawaban ini adalah sampah
Jonathan Taylor
-2

Anda sebenarnya dapat mencapai ini, di Chrome dan FireFox.

Coba url berikut, ini akan mengunduh kode yang digunakan.

data:text/html;base64,PGEgaHJlZj0iZGF0YTp0ZXh0L2h0bWw7YmFzZTY0LFBHRWdhSEpsWmowaVVGVlVYMFJCVkVGZlZWSkpYMGhGVWtVaUlHUnZkMjVzYjJGa1BTSjBaWE4wTG1oMGJXd2lQZ284YzJOeWFYQjBQZ3BrYjJOMWJXVnVkQzV4ZFdWeWVWTmxiR1ZqZEc5eUtDZGhKeWt1WTJ4cFkyc29LVHNLUEM5elkzSnBjSFErIiBkb3dubG9hZD0idGVzdC5odG1sIj4KPHNjcmlwdD4KZG9jdW1lbnQucXVlcnlTZWxlY3RvcignYScpLmNsaWNrKCk7Cjwvc2NyaXB0Pg==
Chad Scira
sumber