Chrome扩展程序如何将许多文件保存到用户指定的目录中

How can a Chrome extension save many files to a user-specified directory?

本文关键字:用户 保存 程序 扩展 文件 许多 Chrome      更新时间:2023-09-26

我正在开发一个用作内部工具的Chrome扩展程序。其所需行为为:

  1. 作为页面操作,在查看某些 Intranet 页面时启用地址栏图标。
  2. 当用户单击图标时,标识页面上特定媒体类型(例如.jpg)的所有文件,以及
  3. 以静默方式将它们全部保存到用户本地驱动器上的目录中。

这个问题以前有人问过,但当时的答案是"使用NPAPI",NPAPI现在已经废弃了。

那么,目前实现这一目标的方法是什么?我看过的是:

  • 铬。文件系统 API ---但这不会将文件保存在任何用户可访问的位置。相反,存储的文件隐藏在未记录目录中模糊名称后面。用户要求将文件以其原始名称存储在可访问的目录中。
  • HTML5 下载属性,通过创建 data: URL 并以编程方式单击它。这将弹出"另存为..."对话框,当单个页面上有一百个资产时,这是不可接受的。用户要求下载文件,除了单击单个图标之外,无需进一步交互。
  • Chrome Download API,但仅在测试版和开发版频道中可用。用户要求此扩展程序适用于主流 Chrome。
  • 通过创建一个小型.exe来使用本机消息传递 API,该仅将文件保存到磁盘,然后将.jpg作为 Blob 传递给它。这似乎非常麻烦,我什至不确定如何可靠地将大型 blob 传递给这样的 EXE。

我可以尝试其他方法吗?

你已经做了很多研究。事实上,常规网页在没有任何插件或扩展名的情况下无法写入用户的文件系统。此外,正如您所观察到的,HTML5 文件系统 API 仅提供对虚拟文件系统的访问。

但是,您将chrome.fileSystem API 与 HTML5 文件系统 API 混淆了。与HTML文件系统API不同,Chrome的fileSystem(应用程序)API可以直接写入用户的文件系统(例如 ~/Documents%USERPROFILE%'Documents ),由用户指定。

此 API 仅适用于 Chrome 应用,不适用于扩展程序。这不是问题,尤其是因为您正在开发内部工具,因为您可以安装应用和扩展,并使用消息传递在扩展(页面操作)和应用(文件系统访问)(示例)之间进行通信。


关于chrome.downloads:由于您的扩展是内部的,因此您可能可以强制用户进入 beta/dev 频道以使用此 API。此 API 的唯一限制是文件将保存在用户定义的下载文件夹(子目录)中。

编辑:chrome.downloads API现在可以在所有渠道中使用,包括稳定分支(自Chrome 31以来)。

恐怕你已经做了功课,这意味着你已经研究了所有可能的替代方案。

实现您想要的最好方法是(如您所提到的)使用支持的本机应用程序并通过本机消息传递进行通信。顺便说一句,由于带宽在内部网上很少成为问题,您可能会发现传递资源(例如图像)URL 并让应用程序下载并保存它们更简单。
(是的,这将比简单地开发扩展更麻烦,但一个人必须做他们必须做的事情,对吧?

另一方面,如果你愿意牺牲一点用户体验而不是简单的开发,我建议将HTML5好东西(允许你在本地创建和下载文件)与JS压缩库(例如JSZip)结合起来,这样用户只需要下载一个zip文件(并且只提示一次)。顺便说一句,如果用户愿意,他/她可以选择始终下载文件而不提示(但您已经知道了)。

使用本机消息传递应用程序的想法。

本机应用程序很麻烦,编写起来很痛苦,因为文档很差,除非你在两端都得到完全正确的 JSON 格式,否则您将不会在控制台中看到任何内容,因为 stdin 和 stdout 被接管了。

但是,当它完成时,你会更快乐,因为您可以使用标准工具(例如,Windows资源管理器,十六进制编辑器,TeamViewer...)来查看,移动和删除文件,否则查看正在发生的事情。 Chrome的沙盒文件系统可以工作,但现在似乎是一个死胡同(没有其他浏览器选择它)。 没有人可能为它开发第三方工具。 当然,一旦一切正常,您可能不需要工具,但在此之前,调试是一场噩梦,因为您需要编写代码(以及相当多的代码)来跟踪哪些文件位于哪些目录中、文件版本、剩余磁盘空间......

内部(或可能是非内部)使用的另一种解决方案是连接到本地或远程的websocket服务器。

您可以将其放在背景.js或内容中.js(使用wss://进行https://

var ws = new WebSocket('ws://echo.websocket.org');
// var ws = new WebSocket('ws://127.0.0.1:9000');
ws.onmessage = function(res) {
    console.log('received data:', res.data);
};
ws.onopen = function() {
    ws.send('hello');
};