Javascript 在打开保存对话框之前写入文件

Javascript 在打开保存对话框之前写入文件,javascript,node.js,vue.js,electron,Javascript,Node.js,Vue.js,Electron,我正在用electron开发一个应用程序。完成一些加密操作后,我需要向用户显示一个对话框来保存文件。我想给文件的文件名是一个随机散列,但我也没有成功。我正在尝试使用此代码,但文件将不会保存。我怎样才能解决这个问题 const downloadPath = app.getPath('downloads') ipcMain.on('encryptFiles', (event, data) => { let output = []; const password = data.pass

我正在用electron开发一个应用程序。完成一些加密操作后,我需要向用户显示一个对话框来保存文件。我想给文件的文件名是一个随机散列,但我也没有成功。我正在尝试使用此代码,但文件将不会保存。我怎样才能解决这个问题

const downloadPath = app.getPath('downloads')

ipcMain.on('encryptFiles', (event, data) => {
  let output = [];
  const password = data.password;
  data.files.forEach( (file) => {
    const buffer = fs.readFileSync(file.path);
    const dataURI = dauria.getBase64DataURI(buffer, file.type);
    const encrypted = CryptoJS.AES.encrypt(dataURI, password).toString();
    output.push(encrypted);
  })
  const filename = hash.createHash('md5').toString('hex');
  console.log(filename)
  const response = output.join(' :: ');
  dialog.showSaveDialog({title: 'Save encrypted file', defaultPath: downloadPath }, () => {
    fs.writeFile(`${filename}.mfs`, response, (err) => console.log(err) )  
  })
})

您遇到的问题是由Electron的UI函数的异步性质造成的:它们不接受回调函数,而是返回承诺。因此,您不必传入回调函数,而是处理承诺的解析。请注意,这仅适用于Electron>=版本6。但是,如果您运行的是较旧版本的Electron,那么您的代码将是正确的——但是您应该真正更新到较新的版本(Electron v6在一年多前发布)

像下面这样调整代码可以作为解决问题的起点。但是,由于您没有说明如何生成哈希(hash.createHash从何而来?;您是否忘记声明/导入
hash
?;您是否忘记传递任何消息字符串?;您是否使用
hash
作为NodeJS的
加密
模块的别名?),它是(此时)无法调试为什么您没有从
console.log(文件名)
获得任何输出(我假设您的意思是“在代码中,将不会创建随机文件名”)。一旦你提供了这个问题的更多细节,我很乐意相应地更新这个答案

至于默认文件名:根据,您可以将文件路径传递到
dialog.showsavedilog()
中,为用户提供默认文件名

您正在使用的文件类型扩展名实际上也应该与文件扩展名一起传递到“保存”对话框中。此外,将此文件扩展名作为筛选器传递到对话框将阻止用户选择任何其他文件类型,这最终也是您当前通过将其附加到文件名所做的

此外,您还可以使用CryptoJS生成文件名:给定一些任意字符串(实际上可能是随机字节),您可以这样做:
filename=CryptoJS.MD5('some text here')+'.mfs'数据。密码
)本质上是不安全的。这里有一些关于如何在互联网上用JavaScript创建随机字符串的好例子,以及其他一些例子

考虑到所有这些问题,最终可能会得到以下代码:

const downloadPath=app.getPath('downloads'),
路径=要求(“路径”);
ipcMain.on('encryptFiles',(事件、数据)=>{
让输出=[];
const password=data.password;
data.files.forEach((文件)=>{
const buffer=fs.readFileSync(file.path);
const dataURI=dauria.getBase64DataURI(缓冲区,file.type);
const encrypted=CryptoJS.AES.encrypt(dataURI,password.toString();
输出推送(加密);
})
//不工作:
//const filename=hash.createHash('md5').toString('hex')+'.mfs';
//另一个选择需要更多的研究在你的端
const filename=CryptoJS.MD5('replace me with some random bytes')+'.mfs';
log(文件名);
const response=output.join(“:”);
dialog.showsavedilog(
{
标题:“保存加密文件”,
defaultPath:path.format({dir:downloadPath,base:filename}),//构造正确的路径
筛选器:[{name:'加密文件(*.mfs)],扩展名:['mfs']}]//筛选可能的文件
}
)。然后((结果)=>{
if(result.cancelled)return;//完全放弃结果;用户已单击“取消”
否则{
var filePath=result.filePath;
如果(!filePath.endsWith('.mfs')){
//这是一个额外的安全检查,不应实际触发。
//但是,通常情况下,在文件名后附加文件扩展名并不是一个好方法
//好主意,因为没有这张支票他们(可能)会加倍。
filePath+='.mfs';
}
fs.writeFile(文件路径,响应,(err)=>console.log(err))
}
}).catch((错误)=>{
console.log(err);
});
})

如果您自己为文件创建一个随机文件名,当用户无法更改文件名时,为什么还要显示一个保存对话框?@AlexanderLeithner通过保存对话框,用户将能够更改文件名。在代码中,将不会创建随机文件名,我还需要修复此问题。在electron文档中,没有解释如何为对话框提供文件名和路径,我看到您使用了专用函数,我将按照您的建议修复代码。对于我现在使用的随机文件名
crypto
模块,我正在调用
randomBytes
,它按照预期工作。我使用的函数
path.format()
,实际上就是为了构建一个你的应用程序运行时可以理解的操作系统路径(Windows使用反斜杠作为路径分隔符,Linux、macOS、BSD等使用正斜杠)。您可以只传递一个普通字符串,但这不能保证在任何地方都有效。文件名传递给Electron的方式如文件所述,是通过
选项
对象的
defaultPath
参数传递的(如您所见).顺便说一句,使用
randomBytes
是一个很好的决定。