使用HTML5/Javascript生成并保存文件

Toj*_*oji 305 javascript html5 download

我最近一直在摆弄WebGL,并且让Collada读者工作了.问题是它很慢(Collada是一种非常冗长的格式),所以我将开始将文件转换为更易于使用的格式(可能是JSON).事实是,我已经有了用Javascript解析文件的代码,所以我也可以将它用作我的导出器!问题在于节省.

现在,我知道我可以解析文件,将结果发送到服务器,并让浏览器从服务器请求文件作为下载.但实际上服务器与这个特定的进程没有任何关系,为什么要让它参与其中呢?我已经在内存中拥有所需文件的内容.有什么方法可以使用纯javascript向用户提供下载吗?(我怀疑它,但不妨问......)

并且要明确:我没有在用户不知情的情况下尝试访问文件系统!用户将提供一个文件(可能通过拖放),脚本将转换内存中的文件,并提示用户下载结果.就浏览器而言,所有这些都应该是"安全"的活动.

[编辑]:我没有提及它,所以回答"Flash"的海报是有效的,但我正在做的部分是尝试强调纯HTML5可以做什么...所以Flash是在我的情况下.(虽然对于任何正在使用"真实"网络应用程序的人来说,这是一个非常有效的答案.)在这种情况下,除非我想要涉及服务器,否则看起来我运气不好.不管怎么说,还是要谢谢你!

Mat*_*rný 265

HTML5就绪浏览器的简单解决方案......

function download(filename, text) {
    var pom = document.createElement('a');
    pom.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
    pom.setAttribute('download', filename);

    if (document.createEvent) {
        var event = document.createEvent('MouseEvents');
        event.initEvent('click', true, true);
        pom.dispatchEvent(event);
    }
    else {
        pom.click();
    }
}
Run Code Online (Sandbox Code Playgroud)

用法

download('test.txt', 'Hello world!');
Run Code Online (Sandbox Code Playgroud)

  • 设置文件名的功能使其成为赢家. (30认同)
  • 此方法适用于Chrome,直到我几天前收到的最新更新(35.0.1916.114 m).现在它部分工作,文件名和扩展名不再起作用(无论传递什么,它总是将文件命名为download.txt.) (9认同)
  • 我有Chrom 42.0.2311.90,这对我有预期的文件名. (5认同)
  • 对FF30也不起作用. (4认同)
  • 是否可以包含的数据量有限制? (3认同)
  • 如果您知道要下载的源URL,那么这是最佳解决方案! (2认同)
  • 很酷。这是它在行动中的 JSFiddle:http://jsfiddle.net/jjorsett/VkRL6/ (2认同)
  • @Druzion Firefox:∞,边缘:4 GB,Chrome:[仅2 MB](https://craignicol.wordpress.com/2016/07/19/excellent-export-and-the-chrome-url-limit/) ? (2认同)

小智 248

好的,创建一个数据:URI肯定对我有用,感谢Matthew和Dennkster指出这个选项!基本上我是这样做的:

1)将所有内容放入称为"内容"的字符串中(例如,通过最初创建它或通过读取已构建页面的标签的innerHTML).

2)构建数据URI:

uriContent = "data:application/octet-stream," + encodeURIComponent(content);
Run Code Online (Sandbox Code Playgroud)

根据浏览器类型等,会有长度限制,但例如Firefox 3.6.12至少可以工作256k.使用encodeURIComponent在Base64中进行编码可能会提高效率,但对我来说还可以.

3)打开一个新窗口并将其"重定向"到此URI,提示我生成JavaScript页面的下载位置:

newWindow = window.open(uriContent, 'neuesDokument');
Run Code Online (Sandbox Code Playgroud)

而已.

  • 如果您想避免使用可能被阻止的弹出窗口,可以将`location.href`设置为内容.`location.href = uriContent`. (33认同)
  • 我认为我们正在努力使它变得更加困难.在这个页面上打开你的JS控制台并把它放在`location.href ="data:application/octet-stream,"+ encodeURIComponent(jQuery('#answer-4551467 .post-text').first().text()) ;`它将保存@Nøk对文件的回答内容.我没有IE来测试它,但它适用于webkit. (25认同)
  • 嗨,我试过这个,但它下载文件为.part文件.我该如何设置文件类型? (12认同)
  • IE并不是真正的数据URI,Firefox似乎用随机名称保存文件. (7认同)
  • @SedatBaşar数据URI不支持设置文件名,您必须依赖浏览器使用mime类型设置适当的扩展名.但是如果mime类型可以由浏览器呈现,它将不会下载它,但它会显示它.还有其他一些方法可以做到这一点,但在IE <10中都没有. (6认同)
  • 数据uri方案支持设置mime类型,维基百科的文章有一些例子http://en.wikipedia.org/wiki/Data_URI_scheme#Examples (2认同)

pan*_*nzi 79

HTML5定义了一种window.saveAs(blob, filename)方法.现在任何浏览器都不支持它.但是有一个名为FileSaver.js的兼容性库,它将此功能添加到大多数现代浏览器(包括Internet Explorer 10+)中.Internet Explorer 10支持一种navigator.msSaveBlob(blob, filename)方法(MSDN),该方法在FileSaver.js中用于Internet Explorer支持.

我写了一篇博客文章,详细介绍了这个问题.

  • W3C表示:已经停止了对该文档的处理,不应将其作为实施的基础. (15认同)
  • FileSaver.js现在支持IE (6认同)

bcm*_*inc 46

保存大文件

长数据URI可能会在浏览器中产生性能问题.保存客户端生成的文件的另一个选项是将其内容放在Blob(或File)对象中并使用创建下载链接URL.createObjectURL(blob).这将返回一个可用于检索blob内容的URL.blob存储在浏览器中,直到URL.revokeObjectURL()在URL上调用或创建它的文档被关闭.大多数Web浏览器都支持对象URL,Opera Mini是唯一不支持对象URL的浏览器.

强制下载

如果数据是文本或图像,则浏览器可以打开文件,而不是将其保存到磁盘.要在单击链接时下载文件,可以使用该download属性.但是,并非所有Web浏览器都支持下载属性.另一种选择是使用application/octet-stream文件的mime类型,但这会导致文件显示为二进制blob,如果您不指定或不能指定文件名,则特别是用户不友好.另请参阅" 强制打开"另存为..."在文本链接中打开弹出窗口,单击HTML中pdf ".

指定文件名

如果使用File构造函数创建blob,您还可以设置文件名,但只有少数Web浏览器(包括Chrome和Firefox)支持File构造函数.文件名也可以指定为download属性的参数,但这需要考虑大量安全性.Internet Explorer 10和11提供了自己的方法msSaveBlob来指定文件名.

示例代码

var file;
var data = [];
data.push("This is a test\n");
data.push("Of creating a file\n");
data.push("In a browser\n");
var properties = {type: 'text/plain'}; // Specify the file's mime-type.
try {
  // Specify the filename using the File constructor, but ...
  file = new File(data, "file.txt", properties);
} catch (e) {
  // ... fall back to the Blob constructor if that isn't supported.
  file = new Blob(data, properties);
}
var url = URL.createObjectURL(file);
document.getElementById('link').href = url;
Run Code Online (Sandbox Code Playgroud)
<a id="link" target="_blank" download="file.txt">Download</a>
Run Code Online (Sandbox Code Playgroud)


Yas*_*azk 33

function download(content, filename, contentType)
{
    if(!contentType) contentType = 'application/octet-stream';
        var a = document.createElement('a');
        var blob = new Blob([content], {'type':contentType});
        a.href = window.URL.createObjectURL(blob);
        a.download = filename;
        a.click();
}
Run Code Online (Sandbox Code Playgroud)

  • contentType有什么影响?它是干什么用的? (3认同)
  • 即使在最新的Chrome中,这个也不错,不像@MatějPokorný的回答.谢谢. (3认同)
  • 这对我在FF36或IE11上不起作用.如果我使用`doc.jPokorný建议的`document.createEvent()`替换`a.click`代码,它适用于FF但不适用于IE.我还没试过Chrome. (2认同)

Pek*_*ica 25

看看Doug Neiner的Downloadify,这是一个基于Flash的JavaScript界面​​来实现这一目标.

Downloadify是一个很小的JavaScript + Flash库,可以在浏览器中动态生成和保存文件,无需服务器交互.

  • 这不符合*使用HTML5 ...*标题的问题. (17认同)
  • 对于大多数人来说,这可能是他们需要的答案.因此即使它不符合我的具体要求(如上所述),我也将其标记为已接受的答案. (6认同)
  • @Ixx很公平,这是在答案发布后添加的.不过,你是对的.应接受以下答案 (5认同)
  • @Toji啊,我明白了.也许在"HTML 5"横幅下重新询问和重新短语并相应标记?这可能会吸引那些了解该特定领域的用户(我现在仍然是一个相对较小的人群,我猜).我很确定它可以在HTML 5中完成,但我不知道如何. (2认同)

T.T*_*dua 16

简单方案!

<a download="My-FileName.txt" href="data:application/octet-stream,HELLO-WORLDDDDDDDD">Click here</a>
Run Code Online (Sandbox Code Playgroud)

适用于所有现代浏览器.

  • @yucer`window.open()`没有下载属性(或与此有关的任何属性)。没关系 您可以使用此方法并在其上强制使用一个.click(),但是要注意时间安排,因为如果在将元素附加到主体之前调用`.click()`,Firefox将不喜欢它。 (2认同)

Mat*_*hen 10

您可以生成数据URI.但是,存在特定于浏览器的限制.


Raz*_*hel 10

我使用过FileSaver(https://github.com/eligrey/FileSaver.js),它运行得很好.
例如,我执行此功能来导出页面上显示的日志.
你必须传递一个数组用于Blob的实例化,所以我可能没有以正确的方式写这个,但它对我有用.
为了以防万一,请小心替换:这是使这个全局化的语法,否则它只会替换他遇到的第一个.

exportLogs : function(){
    var array = new Array();

    var str = $('#logs').html();
    array[0] = str.replace(/<br>/g, '\n\t');

    var blob = new Blob(array, {type: "text/plain;charset=utf-8"});
    saveAs(blob, "example.log");
}
Run Code Online (Sandbox Code Playgroud)

  • FileSaver很棒,这里是一个IE Shim for IE10之前的函数preIE10SaveAs :( filename,filecontent,mimetype){var w = window.open(); var doc = w.document; doc.open(mimetype,'replace'); doc.charset ="utf-8"; doc.write(filecontent); doc.close(); doc.execCommand("SaveAs",null,filename); } (2认同)

mai*_*kel 8

我找到了两种适合我的简单方法.首先,使用已经单击的a元素并注入下载数据.第二,生成a带有下载数据的元素,a.click()再次执行和删除它.但第二种方法只有在用户点击操作调用时才有效.(某些)click()来自其他上下文的浏览器阻塞,例如加载或超时后触发(setTimeout).

<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="UTF-8">
    <script type="text/javascript">
      function linkDownload(a, filename, content) {
        contentType =  'data:application/octet-stream,';
        uriContent = contentType + encodeURIComponent(content);
        a.setAttribute('href', uriContent);
        a.setAttribute('download', filename);
      }
      function download(filename, content) {
        var a = document.createElement('a');
        linkDownload(a, filename, content);
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
      }
    </script>
   </head>
  <body>
    <a href="#" onclick="linkDownload(this, 'test.txt', 'Hello World!');">download</a>
    <button onclick="download('test.txt', 'Hello World!');">download</button>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

  • 您还可以将`a`插入到文档中(可能使用`"display:none"`),单击它,然后将其删除. (2认同)

Den*_*ter 6

这是Mathew建议的数据URI方法的链接,它在safari上工作,但不好,因为我无法设置文件类型,它被保存为"未知",然后我必须再次去那里并按顺序更改它查看文件...

http://www.nihilogic.dk/labs/canvas2image/


Kam*_*ski 6

尝试

let a = document.createElement('a');
a.href = "data:application/octet-stream,"+encodeURIComponent('"My DATA"');
a.download = 'myFile.json';
a.click(); // we not add 'a' to DOM so no need to remove
Run Code Online (Sandbox Code Playgroud)

如果你想下载二进制数据看这里

更新

2020.06.14 我将 Chrome 升级到 83.0 及更高版本 SO 代码段停止工作(由于沙箱安全限制) - 但 JSFiddle 版本有效 -在这里