electron [Feature Request]: Allow Generating Blobs from File Paths

sbdsn5lh  于 22天前  发布在  Electron
关注(0)|答案(6)|浏览(19)

预检清单

问题描述

当前解决方案

一个未沙盒化的electron预加载器具有 Blob 类以及 'fs' 模块。
以下代码确实提供了从文件路径到 Blob 和反向转换的方法:

const fs = require('fs');

// convert system file into blob
function fileToBlob(path, {bufferSize=64*1024}={}) {
	return new Promise((resolve,reject) => {
		// create incoming stream from file
		const stream = fs.createReadStream(path, {highWaterMark:bufferSize});

		// initialize empty blob
		var blob = new Blob([]);

		stream.on('data', buffer => {
			// append each chunk to blob by building new blob concatenating new chunk
			blob = new Blob([blob, buffer]);
		});
		stream.on('close', () => {
			// resolve with resulting blob
			resolve(blob);
		});
	});
}

// convert blob into system file
function blobToFile(blob,path, {bufferSize=64*1024}={}) {
	return new Promise((resolve,reject) => {
		// create outgoing stream to file
		const stream = fs.createWriteStream(path);

		stream.on('ready', async () => {
			// iterate chunks at a time
			for(let i=0; i<blob.size; i+=bufferSize) {
				// read chunk
				let slice = await blob.slice(i, i+bufferSize).arrayBuffer();

				// write chunk
				if(!stream.write(new Uint8Array(slice))) {
					// wait for next drain event
					await new Promise(resolve => stream.once('drain', resolve));
				}
			}

			// close file and resolve
			stream.on('close', () => resolve());
			stream.close();
		});
	});
}

module.exports = {
	fileToBlob,
	blobToFile,
};

当前解决方案的问题

对于小文件,这没有任何缺点,运行良好。但是当处理多兆字节文件时,这是非常不切实际和缓慢的,因为它需要逐字节读取和复制整个文件。

Chromium现有机制

现在,Chromium已经支持立即生成文件到blob(一种将blob直接附加到文件的类型;如果文件被修改,blob也会改变)。这在拖放API以及 <input type="file"> 输入中很明显。
相反,Chromium也支持相当快速的blob到文件生成。这可以在创建blob URL并下载它时看到(它实际上是以操作系统级别的文件复制速度下载;所以,足够了,但不是技术上的即时)。

建议的添加

由于blob对于许多渲染上下文操作(如播放视频: https://stackoverflow.com/questions/59133969/play-a-blob-video-file )是必需的,并且通常用于大文件,因此变得非常必要能够立即使用Chromium在其拖放API中的相同机制从文件生成blob。
反过来,对于修改blob(例如通过切片、生成和重新连接到新blob)的应用程序来说,能够以原生速度导出blob也是非常有帮助的,同样使用Chromium或类似机制。具体来说,虽然可以通过通过blob URL下载blob来实现这一点,但这种机制将避免下载文件对话框。

建议的解决方案

有许多方法可以实现这一点。一种简单的、直接的方法可以在启用了 nodeIntegration 的预加载器或渲染器上对electron模块进行一些 blobToFile / fileToBlob 方法:

const { fileBlob } = require('electron');

// generate blob from file
var blob = fileBlob.fileToBlob("C:/Users/Example/Desktop/foo.txt");

var newBlob = new Blob( [blob.slice(100,200), blob.slice(0,100)] );

// save blob to file
fileBlob.blobToFile("C:/Users/Example/Desktop/foo-reversed.txt");

请注意,上述函数是同步编写的,但异步方法也可以。
然而,我知道,由于Blob在node.js中不受支持,如果没有某种Blob polyfill,像'fileBlob'这样的模块将无法在node.js electron模块中使用。我的主要请求是在至少渲染器预加载器环境中提供一种方法。

考虑过的其他方案

我找到了以下类似的请求存在,问题 #749 ,它建议使文件输入的值可修改。解决该问题也将解决此问题。解决此问题不会为该问题提供精确的解决方案,但在大多数(或可能所有)情况下都会足够。

bnlyeluc

bnlyeluc1#

我强烈觉得我们需要这个功能。
我的用例:在一个医疗应用中,文件存储在本地文件系统(其路径存储在IndexDB数据库中),需要通过一个以blob格式访问的模块来访问这些文件。这个模块来自第三方,所以不能更改它。

2mbi3lxu

2mbi3lxu2#

我需要这个功能:filePathToBlob()

vmdwslir

vmdwslir3#

嘿,Andrew,感谢你认真的撰写和提议!
我不知道是否已经计划了这项工作,但为了澄清——我认为你是建议自己编写这个提案,但从你的撰写中我不确定,所以我想问一下而不是做出假设?
如果你自愿参与这个提案的工作,那么我认为下一步应该是将这个提案转发给API工作组进行审查。

tpgth1q7

tpgth1q74#

感谢@ckerr。
我的目的只是提出这个功能。即使如此,如果我熟悉Electron/Chromium代码库,我也愿意自己编写它。我可以尝试添加这个功能吗?还是最好让熟悉该代码区域的人来帮助避免bug/安全漏洞?
如果你不认为这很重要,也许可以帮我指明正确的方向(我以前没有为electron贡献过)。我不反对尝试,我完全愿意帮助使一个已经很棒的项目变得更好😄。

eit6fx6z

eit6fx6z5#

你好,@CodeSmith32,
听起来很棒,谢谢!在我们讨论实现之前,我认为第一步应该是API工作组审查你的提案,因为那里提出的任何更改都将影响实现。我之前的评论主要是想了解你是否自愿承担这项工作,因为我不希望在没有冠军的情况下向API工作组提出提案😸
CC @electron/wg-api

gudnpqoy

gudnpqoy6#

File System Access API 可以帮助解决这个问题。在最新的夜间测试中,以下代码可以读取文件到 blob:

[fileHandle] = await window.showOpenFilePicker();
  const file = await fileHandle.getFile();
  const newBlob = new Blob( [file.slice(100,200), file.slice(0,100)] );

使用 window.showOpenFilePicker() 的一个注意事项是,它需要用户选择一个文件。此外,似乎将 blob 写入文件会在 Electron 中抛出错误(可能是因为 Chromium 对安全上下文的 File System Access API 限制):

const handle = await window.showSaveFilePicker();
  const writable = await fileHandle.createWritable();  
  await writable.write(newBlob);
  await writable.close();

相关问题