Có cách nào để chỉ định tên tệp được đề xuất khi sử dụng dữ liệu: URI không?


225

Nếu ví dụ bạn theo liên kết:

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

Trình duyệt sẽ nhắc bạn tải xuống một tệp bao gồm dữ liệu được giữ dưới dạng base64 trong chính siêu liên kết. Có cách nào để đề xuất một tên mặc định trong đánh dấu không? Nếu không, có một giải pháp JavaScript?


có thể không liên quan đến vấn đề này nhưng tôi khuyên bạn nên sử dụng blob's & URL.createObjectURL nếu đây không phải là máy chủ hoặc trở ngại trình duyệt cũ
Endless

3
Một số trình duyệt hỗ trợ "tên" tham số tùy chọn của mediatype:data:application/pdf;name=document.pdf;base64,BASE64_DATA_ENCODED
mems

Tôi gặp vấn đề với Firefox pdf.js có xu hướng bị treo trong một số trường hợp nếu nó không thể trích xuất tên tệp từ uri dữ liệu. xem stackoverflow.com/questions/45585921/ Mạnh
Bernhard

@mems Trình duyệt nào hỗ trợ tham số "name"? Bạn có thể chỉ cho tôi một số tài liệu tham khảo? (google-fu của tôi đã làm tôi thất bại).
TheAddonDepot

@DimuDesigns Ít nhất là Firefox tại thời điểm đó. Có vẻ như nó không còn là trường hợp nữa. Nó liên quan đến tham số "tên" Loại nội dung MIME (! = Loại bỏ nội dung) (không phải trong RFC?)
mems

Câu trả lời:


158

Sử dụng downloadthuộc tính:

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

Sống ví dụ về html5-demos.appspot.com / ... .

Hiện đang hoạt động trên Chrome, Firefox, Edge, Opera và Safari trên máy tính để bàn nhưng không phải iOS Safari hoặc IE11.


3
@BioDesign: Nó hoạt động ngay cả với dữ liệu: URI bằng chrome. Xem: jsfiddle.net/pYpqW
Nhận thức

6
nhưng bạn không thể làm điều đó với window.location.replace. nếu bạn muốn tạo dữ liệu: uri hoặc dữ liệu được tạo bởi window.URL.createObjectURLvà tải xuống dưới dạng tệp, bạn sẽ phải tạo <a> và nhấp vào nó: jsfiddle.net/flyingsheep/wpQtH (không, $(...).click()không hoạt động)
cừu bay

1
Chỉ khi tất cả trình duyệt giống như Chrome ... [thở dài]
đèn đường

6
@flyingsheep $('<a href="data:text/plain,Test" download="test.txt">')[0].click()dường như hoạt động tốt ở đây (Chrome 23) (lưu ý: Tôi đã sử dụng clickphương thức gốc , không phải phương thức của jQuery). Bản demo: jsfiddle.net/2zsRW
Rob W

1
@flyingsheep có vẻ như họ đang thực thi chính sách cùng nguồn gốc trong Firefox "Trong Firefox 20, thuộc tính này chỉ được vinh danh cho các liên kết đến các tài nguyên có cùng nguồn gốc." developer.mozilla.org/en-US/docs/Web/HTML/Euity/a Trong thử nghiệm của tôi, Chrome không có giới hạn này.
William Denniss

62

Chrome làm điều này rất đơn giản những ngày này:

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

Idk những gì tất cả những câu trả lời khác đang nói về điều này đã hoạt động trong lần thử đầu tiên trong Chrome 30.
Michael J. Calkins

2
Nó làm bây giờ nhưng không phải lúc nào cũng dễ dàng. Nhiều câu trả lời là từ nhiều năm trước. Và họ cũng làm việc cho các trình duyệt khác.
Holf

7
Tham khảo http://caniuse.com/#feat=d Download để biết danh sách đầy đủ về khả năng tương thích trình duyệt.
tixastronauta

2
@tixastronauta: Mặc dù có thông tin trong trang đó, nhưng không hoạt động trong firefox của tôi 44. Hoạt động tốt trong Chrome. 48
Luis A. Florit 17/2/2016

Xin chào @Holf có cách nào để thêm loại tệp hoặc phần mở rộng hoặc nó chỉ đơn giản như spceficy nó như tên tệp?
Fraccier

51

Chỉ HTML: sử dụng downloadthuộc tính:

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


Chỉ Javascript: bạn có thể lưu bất kỳ URI dữ liệu nào bằng mã này:

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 và Edge 13+ sẽ sử dụng tên tệp được chỉ định.

IE11, Edge 12 và Safari 9 ( không hỗ trợ downloadthuộc tính ) sẽ tải xuống tệp với tên mặc định của họ hoặc họ sẽ chỉ hiển thị nó trong một tab mới, nếu đó là loại tệp được hỗ trợ: hình ảnh, video, tệp âm thanh , Giáo dục


Cả hai bản demo đều hoạt động tốt với tôi trong Chrome 38 (nhưng chúng nên hoạt động trong Chrome 14+)
fregante

Để có giải pháp hoàn chỉnh hơn, tôi khuyên bạn nên sử dụng downloadjsvào
npm

Nó hoạt động với tôi nhưng trang trình duyệt làm mới sau đó. Tự hỏi làm thế nào để ngăn chặn điều đó?

1
Không hoạt động trong chrome cho kích thước tệp> 2MB do hạn chế của chrome stackoverflow.com/questions/695151/
Kẻ

Giới hạn thuộc về data:URI, đó là những gì câu hỏi đề cập. Câu trả lời này cũng hoạt động với Blobs và bất cứ điều gì khác có URI
fregante

40

Theo RFC 2397 , không, không có.

Cũng không có bất kỳ thuộc tính nào của <a>yếu tố mà bạn có thể sử dụng.

Tuy nhiên, HTML5 sau đó đã giới thiệu downloadthuộc tính trên <a>phần tử, mặc dù tại thời điểm viết hỗ trợ không phổ biến (chẳng hạn như không hỗ trợ MSIE)


9
câu thứ hai đúng vào thời điểm viết, nhưng không còn nữa . cho đến nay, nó vẫn chưa được thực hiện rộng rãi.
cừu bay

xem bình luận này để biết thêm :)
cừu bay

@flyingsheep, Nó được thực hiện rộng rãi.
Pacerier 3/03/2015

1
Không phải là 3 năm trước khi tôi viết bình luận đó
cừu bay

Nếu tệp quá dài, quá trình tải xuống không thành công
deFreitas

21

Tôi đã xem một chút trong các nguồn firefox trong netwerk / Protocol / data / nsDataHandler.cpp

trình xử lý dữ liệu chỉ phân tích nội dung / loại và bảng mã và xem nếu có "; base64" trong chuỗi

các đặc tả rfc không có tên tệp và ít nhất firefox xử lý không có tên tệp cho nó, mã tạo ra một tên ngẫu nhiên cộng với ".part"

Tôi cũng đã kiểm tra nhật ký 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

tập tin thú vị nếu bạn muốn xem các nguồn 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

Tôi nghĩ bạn có thể ngừng tìm kiếm một giải pháp ngay bây giờ, vì tôi nghi ngờ là không có :)

như được chú ý trong chủ đề này, html5 có downloadthuộc tính, nó cũng hoạt động trên firefox 20 http://www.whatwg.org/specs/web-apps/cien-work/multipage/links.html#attr-hyperlink-doad


3
Mát mẻ! Mặc dù tôi không nhất thiết phải đồng ý rằng Firefox là cơ quan quyền lực tối thượng đối với những gì tồn tại. :)
Gleno

14

Đoạn mã Javascript sau hoạt động trong Chrome bằng cách sử dụng thuộc tính 'tải xuống' mới của các liên kết và mô phỏng một lần nhấp.

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

Và ví dụ sau đây cho thấy nó sử dụng:

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

1
Điều này không hoạt động trong Firefox, tôi đã thêm một câu trả lời mở rộng bên dưới với khả năng tương thích Fx.
fregante

12

Không.

Toàn bộ mục đích là đó là một kho dữ liệu, không phải là một tệp. Nguồn dữ liệu không nên có bất kỳ kiến ​​thức nào về tác nhân người dùng xử lý nó dưới dạng tệp ... và nó không có.


6
Mục đích của data:việc đưa một khối dữ liệu nội bộ vào định dạng URL mà không cần phải đọc nó từ nguồn dựa trên giao thức. Liên kết trong câu trả lời của @ silex cho thấy khả năng đề xuất một tên ưa thích để viết nó được coi là hữu ích, ngay cả khi nó chưa được triển khai.
Alnitak

1
@Alnitak: Hữu ích? Chắc chắn rồi. Kỹ thuật phù hợp? Vẫn không thuyết phục. :)
Các cuộc đua nhẹ nhàng trong quỹ đạo

3
@Tomalak xem xét sự khác biệt giữa tải dữ liệu và lưu dữ liệu - chỉ vì một blob được mã hóa nội tuyến trong dữ liệu: URL không có nghĩa là nó không nên có một tên ưa thích để lưu nó vào.
Alnitak

4
Nhưng dòng của bạn về "toàn bộ mục đích" là sai. data:được phát minh cụ thể để cho phép (nhỏ) nội dung nội tuyến xuất hiện ở định dạng URL kết hợp với nhau để nó có thể được sử dụng bởi những thứ như thẻ hình ảnh mà không có yêu cầu HTTP riêng. HTML cho biết nội dung của một img srcthuộc tính phải là một URL, vì vậy đó là những gì RFC 2397 đã tạo. Không có "nguồn dữ liệu".
Alnitak

6
@Alnitak: Chính xác. Không có nguồn dữ liệu. Không có bối cảnh. URI dữ liệu.
Các cuộc đua nhẹ nhàng trong quỹ đạo

9

bạn có thể thêm một thuộc tính tải xuống cho phần tử neo.

mẫu vật:

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

5

Nhìn vào liên kết này: http://lists.w3.org/Archives/Public/uri/2010Feb/0069.html

Trích dẫn:

Nó thậm chí hoạt động (như trong, không gây ra vấn đề gì) với; base64 ở cuối
như thế này (ít nhất là trong Opera):

dữ liệu: text / plain; charset = utf-8; headers = Content-Disposeition% 3A% 20attachment% 3B% 20filename% 3D% 22with% 20spaces.txt 3D

Ngoài ra có một số thông tin trong các thông điệp còn lại của cuộc thảo luận.


tiếc là cái này không tải được.
James Khoury

7
cuộc thảo luận này là một phần mở rộng được đề xuất cho định dạng URI dữ liệu - nó đã không được thực hiện.
Alnitak

Được thực hiện hay không, với sự hỗ trợ hiện có cho các tham số tùy ý, đây sẽ là một điều tuyệt vời.
Dan Lugg

5

Sử dụng nhân viên phục vụ , điều này cuối cùng có thể theo nghĩa thật nhất.

  1. Tạo một URL giả. Ví dụ: /saveAs/myPrettyName.jpg
  2. Sử dụng URL trong <a href, <img src , window.open (url), hoàn toàn mọi thứ có thể được thực hiện với một URL "thực".
  3. Bên trong công nhân, bắt sự kiện tìm nạp và trả lời với dữ liệu chính xác.

Trình duyệt hiện sẽ đề xuất myPrettyName.jpg ngay cả khi người dùng mở tệp trong tab mới và cố lưu nó ở đó. Nó sẽ chính xác như thể tập tin đến từ máy chủ.

// 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
Hấp dẫn! Hiện tại, hỗ trợ có vẻ khá nông cạn: caniuse.com/#feat=serviceworkers
tuomassalo 6/2/2015

Có cách nào để "trả lời" với một url trực tiếp khác vào một tệp không?
Iulian Onofrei

4

Có một kịch bản giải pháp nhỏ trên Google Code phù hợp với tôi:

http://code.google.com.vn/p/doad-data-uri/

Nó thêm một biểu mẫu với dữ liệu trong đó, gửi nó và sau đó xóa biểu mẫu lại. Hacky, nhưng nó đã làm công việc cho tôi. Yêu cầu jQuery.

Chủ đề này đã xuất hiện trong Google trước trang Google Code và tôi nghĩ rằng nó cũng hữu ích khi có liên kết ở đây.


Kịch bản thú vị nhưng nó đòi hỏi máy chủ phải nhận được phản hồi và gửi lại đúng không? jsfiddle.net/hZySf
James Khoury

Tôi không chắc tệp được tạo từ đâu .. tệp đó có được lưu trong mã hóa base64 không? (Tôi không quá quen thuộc với cơ sở64)
đèn đường

@streetlight: "Tệp" (tức là dữ liệu) được tạo bởi Javascript. Bối cảnh của dự án đó (và có lẽ hầu hết ở đây) cho rằng bạn có một số cách để đưa dữ liệu mong muốn của bạn vào một biến JS. Sự khác biệt là thay vì trình bày nó cho người dùng thông qua data:...URI, tập lệnh đó tạo ra một biểu mẫu để POST nó cho máy chủ. Và sau đó, máy chủ có lẽ lặp lại ngay lập tức dưới dạng phản hồi "tải xuống" HTTP (nghĩa là với tiêu đề Xử lý nội dung phù hợp chỉ định tên tệp).
Andrzej Doyle

4

Đây là phiên bản jQuery dựa trên phiên bản của Holf và hoạt động với Chrome và Firefox trong khi phiên bản của anh ấy dường như chỉ hoạt động với Chrome. Thật kỳ lạ khi thêm một cái gì đó vào cơ thể để làm điều này nhưng nếu ai đó có một lựa chọn tốt hơn thì tôi sẽ làm tất cả.

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

1
Với jQuery 1.11, tôi nhận được một ngoại lệ vì .remove (). Tôi đã khắc phục điều này bằng cách gán $().appendTo()cho một biến sau đó gọivariable.click(); variable.remove()
p0lar_bear

@ p0lar_bear bạn sẽ nhận được ngoại lệ đó với bất kỳ jQuery nào, bởi vì việc lấy [0]từ bất kỳ "phần tử jQuery" nào sẽ trả về phần tử DOM đầu tiên mà nó đại diện, về cơ bản là "đưa bạn ra khỏi" jQuery.
drzaus

Bạn thực sự không cần phải thêm / xóa phần tử nào cả - xem bình luận tại stackoverflow.com/a/17311705/1037948
drzaus

3

Đó là một loại tin tặc, nhưng tôi đã từng ở trong tình trạng tương tự trước đây. Tôi đã tự động tạo một tệp văn bản trong javascript và muốn cung cấp nó để tải xuống bằng cách mã hóa nó bằng URI dữ liệu.

Điều này là có thể với sự can thiệp của người dùng lớn nhỏ . Tạo một liên kết <a href="data:...">right-click me and select "Save Link As..." and save as "example.txt"</a>. Như tôi đã nói, điều này là không phù hợp, nhưng nó hoạt động nếu bạn không cần một giải pháp chuyên nghiệp.

Điều này có thể được thực hiện ít đau đớn hơn bằng cách sử dụng flash để sao chép tên vào bảng tạm. Tất nhiên, nếu bạn cho phép mình sử dụng Flash hoặc Java (bây giờ tôi có hỗ trợ trình duyệt ngày càng ít đi?), Có lẽ bạn có thể tìm một cách khác để làm điều này.


Đây không phải là một giải pháp và không đáp ứng những gì được yêu cầu. Lấy làm tiếc.
jcolebrand

7
Lol @ "can thiệp người dùng nhỏ". Bắt người dùng làm toàn bộ cho bạn không phải là "sự can thiệp của người dùng nhỏ".
Các cuộc đua nhẹ nhàng trong quỹ đạo

Kết hợp điều này với stackoverflow.com/questions/17311645/ trên để kích hoạt liên kết được tạo và bạn không cần sự can thiệp của người dùng. Bạn có thể chỉ định thuộc tính HTML5download để đề xuất một tên như được đề cập bởi nhiều câu trả lời khác .
drzaus

Đây là một cách giải quyết tuyệt vời cho Safari. Sử dụng Modernizr để phát hiện khi thuộc tính tải xuống không được hỗ trợ và cập nhật văn bản liên kết!
littledopero

2

Cái này hoạt động với Firefox 43.0 (cũ hơn chưa được kiểm tra):

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>

Nếu nhấp vào nút, nó cung cấp một tệp có tên hello.bin để tải xuống. Thủ thuật là sử dụng File thay vì Blob .

tham khảo: 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
vui lòng thêm một lời giải thích chi tiết hơn cho câu trả lời của bạn - stackoverflow.com/help/how-to-answer
Sebastian Brosch

1
câu trả lời này là rác
Jonathan Taylor

-2

Bạn thực sự có thể đạt được điều này, trong Chrome và FireFox.

Hãy thử url sau, nó sẽ tải xuống mã đã được sử dụng.

data:text/html;base64,PGEgaHJlZj0iZGF0YTp0ZXh0L2h0bWw7YmFzZTY0LFBHRWdhSEpsWmowaVVGVlVYMFJCVkVGZlZWSkpYMGhGVWtVaUlHUnZkMjVzYjJGa1BTSjBaWE4wTG1oMGJXd2lQZ284YzJOeWFYQjBQZ3BrYjJOMWJXVnVkQzV4ZFdWeWVWTmxiR1ZqZEc5eUtDZGhKeWt1WTJ4cFkyc29LVHNLUEM5elkzSnBjSFErIiBkb3dubG9hZD0idGVzdC5odG1sIj4KPHNjcmlwdD4KZG9jdW1lbnQucXVlcnlTZWxlY3RvcignYScpLmNsaWNrKCk7Cjwvc2NyaXB0Pg==
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.