使用数据时,有什么方法可以指定建议的文件名:URI?


225

例如,如果您点击链接:

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

浏览器将提示您下载一个文件,该文件包含超链接本身中以base64形式保存的数据。有什么办法可以建议标记中的默认名称吗?如果没有,是否有JavaScript解决方案?


也许与这个问题无关,但是我建议使用blob的&URL.createObjectURL(如果这不是服务器或旧版浏览器的障碍)
Endless

3
某些浏览器支持媒体类型的可选参数“名称”:data:application/pdf;name=document.pdf;base64,BASE64_DATA_ENCODED
mems

我遇到了Firefox pdf.js的问题,如果它无法从数据uri中提取文件名,则在某些情况下它会挂起。参见stackoverflow.com/questions/45585921/…–
Bernhard

@mems哪些浏览器支持“ name”参数?您能指出一些参考文档吗?(我的Google Fu使我失败了)。
TheAddonDepot '18

@DimuDesigns当时至少是Firefox。看来情况已不再如此。它与MIME Con​​tent-Type(!= Content-Disposition)“名称”参数(RFC中不存在)有关
mems

Answers:


158

使用download属性:

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

html5-demos.appspot.com / ...上的实时示例。

目前可在 Chrome,Firefox,Edge,Opera和桌面Safari上运行,但不适用于iOS Safari或IE11。


3
@BioDesign:它甚至适用于chrome中的data:URI。请参阅:jsfiddle.net/pYpqW
Senseful

6
但您无法使用window.location.replace。如果您要创建一个data:uri或由生成的数据window.URL.createObjectURL,并将其下载为文件,则必须创建一个<a>并单击它:jsfiddle.net/flyingsheep/wpQtH(不,$(...).click()不起作用)
飞羊

1
只有所有浏览器都像Chrome一样... [叹气]
streetlight 2012年

6
@flyingsheep $('<a href="data:text/plain,Test" download="test.txt">')[0].click()似乎在这里可以正常工作(Chrome 23)(注意:我使用的是本机click方法,而不是jQuery的方法)。演示:jsfiddle.net/2zsRW
Rob W

1
@flyingsheep似乎他们在Firefox中实施了同源策略“在Firefox 20中,该属性仅适用于具有相同起源的资源的链接。” developer.mozilla.org/zh-CN/docs/Web/HTML/Element/a在我的测试中,Chrome没有此限制。
威廉·丹尼斯

62

如今,Chrome使这一过程变得非常简单:

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

Idk所有其他所有答案都在谈论这个问题,这是第一次尝试在Chrome 30中工作的
。– Michael J. Calkins

2
现在可以了,但并不总是那么容易。这些答案中有许多是几年前的。而且它们还适用于其他浏览器。
Holf 2013年

7
有关浏览器兼容性的完整列表,请参见http://caniuse.com/#feat=download
tixastronauta

2
@tixastronauta:尽管有该页面中的信息,但在我的firefox 44中无法正常工作。在Chrome中运行良好。48
Luis A. Florit '16

嗨,@ Holf还有一种方法可以像添加文件名一样简单地添加文件类型或扩展名?
Fraccier '16

51

仅HTML:使用download属性:

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


仅限Javascript:您可以使用以下代码保存任何数据URI:

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和Edge 13+将使用指定的文件名。

IE11,Edge 12和Safari 9不支持该download属性)将使用默认名称下载文件,或者如果文件类型受支持,则将它们仅显示在新标签中:图像,视频,音频文件,…


这两个演示都适合我在Chrome 38中运行(但应该在Chrome 14+中运行)
fregante

有关更完整的解决方案,我建议downloadjs在npm上使用
fregante

它对我有用,但之后浏览器页面刷新。想知道如何预防?

1
在浏览器不工作的文件大小> 2MB由于受铬限制stackoverflow.com/questions/695151/...
Pranav辛格

限制属于data:URI,这就是问题所在。这个答案也适用于Blobs以及其他具有URI的东西
fregante

40

根据RFC 2397,不,没有。

有也没有出现任何属性的的<a>元素,你可以使用。

但是,HTML5随后download<a>元素上引入了属性,尽管在撰写本文时,支持并不普遍(例如,不支持MSIE)


9
第二句话在撰写本文时是正确的,但现在不再适用。到目前为止,它尚未得到广泛实施。
飞羊

有关更多信息,请参阅此评论 :)
飞羊

@flyingsheep,广泛实施。
Pacerier 2015年

1
并不是3年前我写评论的时候
放羊

如果文件很长,下载将失败
deFreitas

21

我在netwerk / protocol / data / nsDataHandler.cpp中的firefox源中看了一些

数据处理程序仅解析内容/类型和字符集,并查看字符串中是否有“; base64”

rfc没有指定文件名,至少firefox对此没有文件名,代码会生成一个随机名称加“ .part”

我还检查了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

如果您想查看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

我认为您现在可以停止搜索解决方案,因为我怀疑没有解决方案:)

正如该线程注意到的html5具有download属性,它也可以在firefox 20上使用http://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#attr-hyperlink-download


3
凉!尽管我不一定同意Firefox是存在的最终权威。:)
Gleno

14

通过使用链接的新“下载”属性并模拟点击,以下Javascript代码段可在Chrome中运行。

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

以下示例说明了它的用法:

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

1
这在Firefox中不起作用,我在下面添加了具有Fx兼容性的扩展答案。
fregante

12

没有。

整个目的是它是一个数据流,而不是一个文件。数据源不应该了解将其作为文件处理的用户代理……也不知道。


6
的目的data:是将内部数据块转换为URL格式,而不必从基于协议的源中读取它。@silex答案中的链接表明,建议将首选名称写入其中的功能被认为是有用的,即使尚未实现也是如此。
Alnitak

1
@Alnitak:有用吗?绝对。技术上合适吗?仍然不服气。:)
轻轨赛将于

3
@Tomalak考虑加载数据和保存数据之间的区别-仅仅是因为blob在数据中以内联方式编码:URL并不意味着它不应该具有用于​​保存到其中的首选名称。
Alnitak

4
但是您关于“整个目标”的观点是错误的。 data:是专门为允许(小的)内联内容以伪造的URL格式显示而发明的,以便图像标签之类的东西可以使用它而无需单独的HTTP请求。HTML表示img src属性的内容必须是URL,这就是RFC 2397创建的内容。没有“数据源”。
Alnitak

6
@Alnitak:是的。没有数据源。没有上下文。URI 数据。
Lightness Races in Orbit

9

您可以将下载属性添加到锚元素。

样品:

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

5

查看此链接:http : //lists.w3.org/Archives/Public/uri/2010Feb/0069.html

引用:

它甚至可以
像这样(至少不会在Opera中)与末尾的; base64一起工作(例如,不会造成问题):

数据:文本/纯文本;字符集= utf-8;标头= Content-Disposition%3A%20attachment%3B%20filename%3D%22with%20spaces.txt%22%0D%0AContent-Language%3A%20en; base64,4oiaDQo% 3D

在讨论的其余消息中也有一些信息。


不幸的是,这无法下载。
詹姆斯·科里

7
此讨论是针对数据URI格式的拟议扩展-尚未实现。
Alnitak

无论是否实现,在现有支持任意参数的情况下,这都将是一个很好的选择。
丹·拉格2012年

5

使用服务人员,这才是真正可能的。

  1. 创建一个伪造的URL。例如/saveAs/myPrettyName.jpg
  2. <a href, <img src,window.open(url)中使用URL ,绝对可以使用“真实” URL完成任何操作。
  3. 在工作进程内部,捕获fetch事件,并使用正确的数据进行响应。

现在,即使用户在新选项卡中打开文件并尝试将其保存在浏览器中,浏览器也会建议myPrettyName.jpg。就像文件来自服务器一样。

// 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
有趣!不过,目前的支持似乎还很薄
tuomassalo 2015年

有什么方法可以使用另一个直接URL“响应”文件吗?
尤利安·奥诺夫雷

4

Google Code上有一个很小的解决方法脚本对我有用:

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

它将添加一个包含数据的表单,提交该表单,然后再次删除该表单。哈基,但它为我做了工作。需要jQuery。

该线程在Google代码页之前显示在Google中,我认为在此链接也可能会有帮助。


有趣的脚本,但是它确实需要服务器来获取响应并将其发送回去吗?jsfiddle.net/hZySf
James Khoury

我不确定文件是从哪里生成的。该文件是以base64编码存储的吗?(我对base64不太熟悉)
路灯

@streetlight:“文件”(即数据)由Javascript生成。该项目的上下文(可能是这里的大多数)假设您有某种方式将所需的数据获取到JS变量中。所不同的是data:...,该脚本不是通过URI 将其呈现给用户,而是创建了一个表单以将其发布到服务器。然后服务器大概会直接回显它,作为HTTP“下载”响应(即,使用适当的Content-Disposition标头指定文件名)。
Andrzej Doyle

4

这是基于Holf版本的jQuery版本,适用于Chrome和Firefox,而他的版本似乎仅适用于Chrome。在身体上添加一些东西来做到这一点有点奇怪,但是如果有人有更好的选择,我全力以赴。

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

1
使用jQuery 1.11时,由于.remove()导致出现异常。通过给$().appendTo()变量赋值然后调用variable.click(); variable.remove()
p0lar_bear,2014年

@ p0lar_bear您应该在任何jQuery中都获得该异常,因为[0]从任何“ jQuery元素”中获取the 都应返回其表示的第一个DOM元素,这实际上“使您脱离了jQuery”。
drzaus 2014年

实际上,您根本不需要添加/删除元素-请参阅stackoverflow.com/a/17311705/1037948的
drzaus 2014年

3

这有点骇人听闻,但我以前也遇到过这种情况。我正在用javascript动态生成一个文本文件,并希望通过使用data-URI对其进行编码来提供下载的文件。

较小的主要用户干预是可能的。生成一个链接<a href="data:...">right-click me and select "Save Link As..." and save as "example.txt"</a>。就像我说的那样,这很不雅致,但是如果您不需要专业的解决方案,它就可以工作。

通过使用Flash首先将名称复制到剪贴板,可以减轻痛苦。当然,如果您允许自己使用Flash或Java(我认为现在对浏览器的支持越来越少了?),您可能会找到另一种方法。


这不是解决方案,不能满足要求。抱歉。
jcolebrand 2011年

7
大声笑@“较小的用户干预”。让用户为您完成全部任务不是“较小的用户干预”。
Lightness Races in Orbit

将此与stackoverflow.com/questions/17311645/…结合以触​​发生成的链接,并且您不需要用户干预。您可以指定HTML5 download属性由提到建议的名称很多 其他 的答案
drzaus 2014年

对于Safari来说,这是一个很好的解决方法。使用Modernizr来检测何时不支持下载属性并更新链接文本!
littledynamo '16

2

此版本适用于Firefox 43.0(旧版本未测试):

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>

如果单击按钮,它将提供一个名为hello.bin的文件供下载。技巧是使用File而不是Blob

参考: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
请添加更详细的解释,以你的答案- stackoverflow.com/help/how-to-answer
塞巴斯蒂安Brosch

1
这个答案是垃圾
乔纳森·泰勒

-2

您实际上可以在Chrome和FireFox中实现这一目标。

尝试以下网址,它将下载所使用的代码。

data:text/html;base64,PGEgaHJlZj0iZGF0YTp0ZXh0L2h0bWw7YmFzZTY0LFBHRWdhSEpsWmowaVVGVlVYMFJCVkVGZlZWSkpYMGhGVWtVaUlHUnZkMjVzYjJGa1BTSjBaWE4wTG1oMGJXd2lQZ284YzJOeWFYQjBQZ3BrYjJOMWJXVnVkQzV4ZFdWeWVWTmxiR1ZqZEc5eUtDZGhKeWt1WTJ4cFkyc29LVHNLUEM5elkzSnBjSFErIiBkb3dubG9hZD0idGVzdC5odG1sIj4KPHNjcmlwdD4KZG9jdW1lbnQucXVlcnlTZWxlY3RvcignYScpLmNsaWNrKCk7Cjwvc2NyaXB0Pg==
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.