nodejs 不用 electron 实现打开文件资源管理器并选择文件

本文介绍了如何在Node.js脚本中利用PowerShell和WindowsFormsAPI实现文件和目录选择,包括单选、多选以及处理中文路径和编码问题,同时提到了MacOS上的相关替代方案。
摘要由CSDN通过智能技术生成

前言

最近在开发一些小脚本,用 nodejs 实现。其中很多功能需要选择一个/多个文件,或者是选择一个文件夹。

最初的实现是手动输入一个目录(这个只是一个普通的终端文本输入,所以按下 tab 没有路径提示),非常的麻烦,而且很容易输错。

这种情况下网上给出的解决方案都是 electron。但是我一个小脚本用 electron 属实有点夸张了,后来转念一想可以通过 powershell 来实现类似的功能。

通过命令唤醒文件选择器

通过 cmd / prowershell 唤醒文件选择器

对 powershell 不熟悉的我唰的一声打开了 gpt,gpt 不负众望 很快给出了答案

注意这里有区别:cmd 终端中需要调用 powershell.exe
如果当前已经是在 powershell 终端的话,直接运行对应的指令即可

  • 在 cmd 中运行:
powershell.exe -Command "& {Add-Type -AssemblyName System.Windows.Forms; $FileDialog = New-Object System.Windows.Forms.OpenFileDialog; $result = $FileDialog.ShowDialog(); if ($result -eq 'OK') { Write-Output $FileDialog.FileName }}"
  • 在 powershell 中运行:
& {Add-Type -AssemblyName System.Windows.Forms; $FileDialog = New-Object System.Windows.Forms.OpenFileDialog; $result = $FileDialog.ShowDialog(); if ($result -eq 'OK') { Write-Output $FileDialog.FileName }}

运行效果:选择文件后终端会输出你选择的文件的全路径

pFSiuTJ.png

在 nodejs 调用 cmd 命令

const { exec, execSync } = require('child_process')

const command = `powershell.exe -Command "& {Add-Type -AssemblyName System.Windows.Forms; $FileDialog = New-Object System.Windows.Forms.OpenFileDialog; $result = $FileDialog.ShowDialog(); if ($result -eq 'OK') { Write-Output $FileDialog.FileName }}"`

// 异步执行
exec(command, (error, file) => {
  console.log(error, file)
})

// 同步执行
const filePath = execSync(command)
console.log('选择的文件', filePath)

到这结束了吗?并没有,我选择的是一个包含中文名称的路径,输入结果如下:

pFSiI10.png

几个小问题:

  1. execSync 同步执行的代码返回的是 Buffer 类型
    • 可以用 filePath.toString()获取实际的路径
  2. 选择的文件/文件夹包含中文,返回乱码的问题
    • 这个需要设置终端的编码类型,也就是在执行上面的命令执行先执行 chcp 650
  3. 遇到执行警告:libpng warning: iCCP: cHRM chunk does not match sRGB
    • 卸载 QQ 拼音 😃 (虽然我也不知道具体是哪里的问题,不过确实是 QQ 拼音引起的)

调整后执行效果如下:

pFSFY3q.png

如何实现多选文件 / 选择文件夹?

  • 选择目录
# 加载 Windows.Forms 程序集
Add-Type -AssemblyName System.Windows.Forms

# 创建 FolderBrowserDialog 对象
$folderDialog = New-Object System.Windows.Forms.FolderBrowserDialog

# 设置对话框的属性
$folderDialog.Description = "请选择文件夹"
$folderDialog.RootFolder = [System.Environment+SpecialFolder]::MyComputer

# 显示文件夹选择对话框
$result = $folderDialog.ShowDialog()

# 检查用户是否点击了 "确定" 按钮
if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
    # 输出所选文件夹的路径
    Write-Output $folderDialog.SelectedPath
} else {
    # 用户取消选择,这里输出空路径
    Write-Output ""
}

合并成一行代码则是:

  • cmd 执行:
powershell.exe -Command "& {Add-Type -AssemblyName System.Windows.Forms; $folderDialog = New-Object System.Windows.Forms.FolderBrowserDialog; $folderDialog.Description = '请选择文件夹'; $folderDialog.RootFolder = [System.Environment+SpecialFolder]::MyComputer; $result = $folderDialog.ShowDialog(); if ($result -eq [System.Windows.Forms.DialogResult]::OK) { Write-Output $folderDialog.SelectedPath } else { Write-Output '' }}"

多选文件同理:

# 加载 Windows.Forms 程序集
Add-Type -AssemblyName System.Windows.Forms

# 创建 OpenFileDialog 对象
$fileDialog = New-Object System.Windows.Forms.OpenFileDialog

# 设置对话框的属性
$fileDialog.Multiselect = $true
$fileDialog.Title = "请选择文件"
$fileDialog.Filter = "All Files (*.*)|*.*"

# 显示文件选择对话框
$result = $fileDialog.ShowDialog()

# 检查用户是否点击了 "确定" 按钮
if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
    # 输出所选文件的路径(数组)
    Write-Output $fileDialog.FileNames
} else {
    # 用户取消选择
    Write-Output ""
}

合并为一行命令:

powershell.exe -Command "& {Add-Type -AssemblyName System.Windows.Forms; $fileDialog = New-Object System.Windows.Forms.OpenFileDialog; $fileDialog.Multiselect = $true; $fileDialog.Title = '请选择文件'; $fileDialog.Filter = 'All Files (*.*)|*.*'; $result = $fileDialog.ShowDialog(); if ($result -eq [System.Windows.Forms.DialogResult]::OK) { Write-Output $fileDialog.FileNames } else { Write-Output '' }}"

一些细节

  • 如果是选择单个文件/选择文件目录。输出的结果会包含一些前后空格和换行,所以需要通过 filePath.trim() 处理一下多余的字符
  • 如果是多选的文件,返回的是字符串,每个文件以换行隔开的,也是需要自行处理
  • 眼尖的朋友可能发现了在多选的命令中有一段代码:$fileDialog.Filter = "All Files (*.*)|*.*" 可以用于设置可选择的文件类型的。
    对应的是这个功能:
    pFSkBsf.png
    就不再细说了~ 自行摸索

MacOS 如何实现用命令打开选择器

以下的命令完全来自 GPT,并没有经过测试。自行判断代码是否正常运行 (原谅我并没有 mac)

  • 选择一个文件
osascript -e 'POSIX path of (choose file with prompt "请选择一个文件")'
  • 选择一个目录
osascript -e 'POSIX path of (choose folder with prompt "请选择一个目录")'
  • 选择多个文件
    (略)gpt 给出的答案非常的长,而且我没电脑试验,所以就不放代码了,有试验过的可以告诉我补充一下~

最后

至此,我的小脚本使用体验已经拉满,再也不用一个个输入文件路径了。

总结下所有用到的命令:

  • Windows

    • 选择单个文件
      powershell.exe -Command "& {Add-Type -AssemblyName System.Windows.Forms; $FileDialog = New-Object System.Windows.Forms.OpenFileDialog; $result = $FileDialog.ShowDialog(); if ($result -eq 'OK') { Write-Output $FileDialog.FileName }}"
    
    • 选择文件目录
    powershell.exe -Command "& {Add-Type -AssemblyName System.Windows.Forms; $folderDialog = New-Object System.Windows.Forms.FolderBrowserDialog; $folderDialog.Description = '请选择文件夹'; $folderDialog.RootFolder = [System.Environment+SpecialFolder]::MyComputer; $result = $folderDialog.ShowDialog(); if ($result -eq [System.Windows.Forms.DialogResult]::OK) { Write-Output $folderDialog.SelectedPath } else { Write-Output '' }}"
    
    • 选择多个文件
    powershell.exe -Command "& {Add-Type -AssemblyName System.Windows.Forms; $fileDialog = New-Object System.Windows.Forms.OpenFileDialog; $fileDialog.Multiselect = $true; $fileDialog.Title = '请选择文件'; $fileDialog.Filter = 'All Files (*.*)|*.*'; $result = $fileDialog.ShowDialog(); if ($result -eq [System.Windows.Forms.DialogResult]::OK) { Write-Output $fileDialog.FileNames } else { Write-Output '' }}"
    
  • MacOS

    • 选择一个文件
    osascript -e 'POSIX path of (choose file with prompt "请选择一个文件")'
    
    • 选择一个目录
    osascript -e 'POSIX path of (choose folder with prompt "请选择一个目录")'
    
    • 选择多个文件

完 ~

要使用ElectronNode.js在浏览器中打开本地视频,你可以使用Node.js的`fs`模块来读取本地视频文件,然后将文件路径作为`<video>`标签的`src`属性值,最后使用Electron的`BrowserWindow`模块来创建一个包含`<video>`标签的窗口。 具体步骤如下: 1. 在你的Electron项目目录下,创建一个视频文件,并将你的本地视频文件放入该文件中。 2. 在你的JavaScript文件中,使用`fs`模块读取本地视频文件,示例代码如下: ```javascript const { app, BrowserWindow } = require('electron'); const path = require('path'); const url = require('url'); const fs = require('fs'); let mainWindow; function createWindow() { mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, }, }); const filePath = path.join(__dirname, '/videos/video.mp4'); // 视频文件路径 const fileExists = fs.existsSync(filePath); if (fileExists) { mainWindow.loadURL(url.format({ pathname: path.join(__dirname, 'index.html'), protocol: 'file:', slashes: true, })); mainWindow.webContents.on('did-finish-load', () => { mainWindow.webContents.send('play-video', filePath); }); } else { console.error('视频文件不存在'); } mainWindow.on('closed', () => { mainWindow = null; }); } app.on('ready', createWindow); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); app.on('activate', () => { if (mainWindow === null) { createWindow(); } }); ``` 其中,`filePath`是你本地视频文件的路径,`fileExists`变量用于判断视频文件是否存在。 3. 在你的HTML文件中,创建一个包含`<video>`标签的页面,示例代码如下: ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>My Video Player</title> </head> <body> <video id="video-player" width="640" height="360" controls> Your browser does not support the video tag. </video> <script src="./renderer.js"></script> </body> </html> ``` 其中,`<video>`标签的`id`属性为`video-player`,`controls`属性用于显示视频控制条。 4. 在你的renderer.js文件中,使用`ipcRenderer`模块来接收主进程发送的视频文件路径,并将其作为`<video>`标签的`src`属性值,示例代码如下: ```javascript const { ipcRenderer } = require('electron'); ipcRenderer.on('play-video', (event, filePath) => { const videoPlayer = document.getElementById('video-player'); videoPlayer.src = `file://${filePath}`; }); ``` 其中,`ipcRenderer.on('play-video', ...)`用于接收主进程发送的视频文件路径,`videoPlayer.src`用于将其作为`<video>`标签的`src`属性值。 5. 运行JavaScript文件,即可通过Electron打开包含`<video>`标签的窗口,自动播放指定的本地视频文件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值