使用HTML5/JavaScript生成并保存文件。
使用HTML5/JavaScript生成并保存文件。
我最近一直在研究WebGL,并成功实现了一个Collada读取器。问题是它的速度很慢(Collada是一种非常冗长的格式),所以我打算将文件转换为更易于使用的格式(可能是JSON)。我已经在JavaScript中编写了解析文件的代码,所以我可能会将其用作导出器!问题在于保存。
现在,我知道我可以解析文件,将结果发送到服务器,并让浏览器从服务器请求文件作为下载。但实际上,服务器与这个特定的过程无关,为什么要涉及它呢?我已经将所需文件的内容保存在内存中。有没有办法使用纯JavaScript向用户提供下载?(我对此表示怀疑,但还是问一下吧...)
并且明确一点:我并不是想在用户不知情的情况下访问文件系统!用户将提供一个文件(可能通过拖放),脚本将在内存中转换文件,并提示用户下载结果。就浏览器而言,所有这些都应该是“安全”的活动。
[编辑]: 我一开始没有提到这一点,所以回答“Flash”的回答是有效的,但我正在尝试突出纯HTML5可以做什么...所以在我的情况下,Flash是不合适的。(尽管对于任何进行“真正”Web应用程序的人来说,这是一个完全有效的答案。)在这种情况下,除非我愿意涉及服务器,否则看起来我运气不佳。谢谢!
使用HTML5/JavaScript生成和保存文件的原因是为了在浏览器中实现文件下载的功能。在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(); } } download('test.txt', 'Hello world!');
这段代码创建了一个``元素,将要下载的文件内容设置为`href`属性的值,并将要保存的文件名设置为`download`属性的值。然后通过模拟点击事件来触发文件下载。这种方法在Chrome浏览器中是完全支持的。
然而,这种方法在最新版本的Chrome中出现了问题,无法正确设置文件名和扩展名(无论传入的参数是什么,都会将文件命名为`download.txt`)。这是因为Chrome最新版本不再支持`download`属性。
另外,Firefox浏览器只有在URL符合同源策略要求时才支持`download`属性。而数据URL似乎不符合这个要求,因为你可以从任何地方获取数据。
这种方法在Chrome中表现良好,但在当前版本的IE和Safari中不起作用,因为它们不支持`download`属性。
对于IE11,可以使用iframe来实现文件下载。以下是一个示例代码:
if (window.navigator.msSaveOrOpenBlob) { var blob = new Blob([text], {type: "text/plain;charset=utf-8;"}); window.navigator.msSaveOrOpenBlob(blob, filename); } else { 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(); } }
需要注意的是,如果将保存按钮放在``标签内部,就不再需要整个`if`-`else`语句。这样做可能还可以增加浏览器的兼容性。
关于可以包含的数据量是否有限制的问题,根据不同的浏览器有不同的限制。Firefox没有限制,Edge的限制是4GB,而Chrome的限制是2MB。
如果想要通过URL下载文件,可以使用类似以下代码的方式替换`"Hello world"`的部分,将S3的预签名URL作为文件下载的源:
download('test.txt', 'http://example.com/file.txt');
需要注意的是,这种方法不适用于从S3下载文件,可以参考这个答案来实现从S3下载文件的功能。
总结起来,使用HTML5/JavaScript生成和保存文件是为了在浏览器中实现文件下载的功能。可以通过创建``元素,设置文件内容和文件名,然后模拟点击事件来实现文件下载。但不同的浏览器对于`download`属性的支持程度不同,需要针对不同的浏览器做处理。此外,使用URL下载文件的方法也是可行的。
使用HTML5/JavaScript生成和保存文件的问题是HTML5定义了一个window.saveAs(blob, filename)
方法,但目前没有任何浏览器支持它。但是有一个兼容性库叫做FileSaver.js,它将这个函数添加到大多数现代浏览器中(包括Internet Explorer 10+)。Internet Explorer 10支持一个navigator.msSaveBlob(blob, filename)
方法(MSDN),FileSaver.js在Internet Explorer中使用这个方法来提供支持。
有关这个问题的更多细节,我写了一个博客文章。
那么弹出窗口的阻止呢?这个库的行为类似于øk的解决方案。在Firefox中,纯文本会在新窗口中打开。只有Chrome会尝试保存它,但它会更改文件扩展名(我需要一个没有扩展名的文件)。
(对象URL+)下载属性变体(我在Chrome中使用)允许您设置文件名。在Chrome中对我有效。
啊哈,如果点击直接导致弹出窗口,它就不会被阻止。
FileSaver接口现在在最新版本的Chrome中得到支持。
不是最新的稳定版本,我猜测?
:我在我的答案中确实链接到了那个库。
FileSaver.js现在支持IE。
W3C表示:对这个文档的工作已经停止,不应将其作为实施的依据引用或使用。
太糟糕了。:/
window.saveAs
在当前草案中不存在:w3.org/TR/2014/CR-html5-20140731/…
我如何在mimeType为application/zip
的情况下使用它?或者我必须使用octet-stream?
您可以在blob上使用任何mime类型(参见Yassir Ennazk的答案)。您只需要在JavaScript中自己生成ZIP文件。我不知道是否有现有的JavaScript ZIP实现。
文件API现在在几乎所有主流浏览器中得到支持 caniuse.com/#feat=fileapi