const { exec, spawn } = require('child_process'); const { promisify } = require('util'); const path = require('path'); const fs = require('fs'); const execAsync = promisify(exec); /** * 检测当前操作系统 */ function getOSPlatform() { const platform = process.platform; if (platform === 'win32') return 'windows'; if (platform === 'darwin') return 'macos'; if (platform === 'linux') return 'linux'; return 'unknown'; } /** * 检查文件或目录是否存在 */ function checkPathExists(targetPath) { try { fs.accessSync(targetPath); return true; } catch (error) { return false; } } /** * 获取目录路径(如果是文件则返回所在目录) */ function getDirectoryPath(targetPath) { try { const stats = fs.statSync(targetPath); if (stats.isFile()) { return path.dirname(targetPath); } if (stats.isDirectory()) { return targetPath; } } catch (error) { throw new Error(`路径不存在或无法访问: ${targetPath}`); } return targetPath; } /** * 在 Windows 系统打开目录 */ async function openDirectoryWindows(directoryPath) { // 确保路径使用反斜杠 const normalizedPath = directoryPath.replace(/\//g, '\\'); console.log(`📁 在文件资源管理器中打开: ${normalizedPath}`); // 方法1: 使用 explorer 命令 try { const command = `explorer "${normalizedPath}"`; await execAsync(command); console.log('✅ 已启动文件资源管理器'); return true; } catch (error) { console.warn('方法1失败:', error.message); } // 方法2: 使用 start 命令 try { const command = `start "" "${normalizedPath}"`; await execAsync(command); console.log('✅ 已使用 start 命令打开'); return true; } catch (error) { console.warn('方法2失败:', error.message); } throw new Error('无法在Windows系统中打开目录'); } /** * 在 macOS 系统打开目录 */ async function openDirectoryMacOS(directoryPath) { console.log(`📁 在访达中打开: ${directoryPath}`); // 方法1: 使用 open 命令 try { const command = `open "${directoryPath}"`; await execAsync(command); console.log('✅ 已启动访达'); return true; } catch (error) { console.warn('方法1失败:', error.message); } // 方法2: 使用 open -R 命令(打开包含指定文件的文件夹) try { const command = `open -R "${directoryPath}"`; await execAsync(command); console.log('✅ 已使用 open -R 命令打开'); return true; } catch (error) { console.warn('方法2失败:', error.message); } throw new Error('无法在macOS系统中打开目录'); } /** * 在 Linux 系统打开目录 */ async function openDirectoryLinux(directoryPath) { console.log(`📁 在文件管理器中打开: ${directoryPath}`); // 尝试不同的文件管理器 const fileManagers = [ 'xdg-open', // 标准Linux桌面打开方式 'nautilus', // GNOME 'dolphin', // KDE 'thunar', // XFCE 'pcmanfm', // LXDE 'nemo', // Cinnamon 'caja' // MATE ]; for (const manager of fileManagers) { try { // 检查文件管理器是否可用 await execAsync(`which ${manager}`); const command = `${manager} "${directoryPath}"`; const child = spawn(manager, [directoryPath], { stdio: 'ignore', detached: true }); child.unref(); console.log(`✅ 已使用 ${manager} 打开目录`); return true; } catch (error) { // 继续尝试下一个文件管理器 continue; } } // 最后尝试 xdg-open(最通用的方式) try { const command = `xdg-open "${directoryPath}"`; const child = spawn('xdg-open', [directoryPath], { stdio: 'ignore', detached: true }); child.unref(); console.log('✅ 已使用 xdg-open 打开目录'); return true; } catch (error) { throw new Error('无法在Linux系统中打开目录,请确保已安装文件管理器'); } } /** * 在终端中打开目录(跨平台) */ async function openDirectoryInTerminal(directoryPath) { const os = getOSPlatform(); const dirPath = getDirectoryPath(directoryPath); console.log(`💻 操作系统: ${os}`); console.log(`📂 目标目录: ${dirPath}`); if (!checkPathExists(dirPath)) { throw new Error(`路径不存在: ${dirPath}`); } switch (os) { case 'windows': return await openDirectoryWindows(dirPath); case 'macos': return await openDirectoryMacOS(dirPath); case 'linux': return await openDirectoryLinux(dirPath); default: throw new Error(`不支持的操作系统: ${process.platform}`); } } /** * 在系统默认终端中打开并切换到目录 */ async function openTerminalInDirectory(directoryPath) { const os = getOSPlatform(); const dirPath = getDirectoryPath(directoryPath); console.log(`🖥️ 在终端中打开目录: ${dirPath}`); if (!checkPathExists(dirPath)) { throw new Error(`路径不存在: ${dirPath}`); } const commands = { windows: `start cmd /K "cd /d "${dirPath}" && echo 当前目录: %cd%"`, macos: `osascript -e 'tell application "Terminal" to do script "cd \\\"${dirPath}\\\" && pwd"'`, linux: `gnome-terminal --working-directory="${dirPath}" || konsole --workdir "${dirPath}" || xterm -e "cd \\"${dirPath}\\" && bash"` }; try { let command; switch (os) { case 'windows': command = commands.windows; break; case 'macos': command = commands.macos; break; case 'linux': command = commands.linux; break; default: throw new Error('不支持的操作系统'); } // 使用 spawn 避免命令注入漏洞 const shell = os === 'windows' ? 'cmd.exe' : '/bin/bash'; const args = os === 'windows' ? ['/c', command] : ['-c', command]; const child = spawn(shell, args, { stdio: 'ignore', detached: true }); child.unref(); console.log('✅ 已启动终端并切换到目录'); return true; } catch (error) { console.warn('无法在终端中打开目录:', error.message); return false; } } /** * 主函数 - 打开文件所在目录 */ async function openFileDirectory(filePath, options = {}) { const { openInTerminal = false, // 是否在终端中打开 createIfNotExists = false, // 目录不存在时是否创建 wait = false // 是否等待进程结束 } = options; try { // 检查路径是否存在 if (!checkPathExists(filePath)) { if (createIfNotExists) { const dirPath = path.dirname(filePath); fs.mkdirSync(dirPath, { recursive: true }); console.log(`📁 创建目录: ${dirPath}`); } else { throw new Error(`路径不存在: ${filePath}`); } } const directoryPath = getDirectoryPath(filePath); if (openInTerminal) { await openTerminalInDirectory(directoryPath); } else { await openDirectoryInTerminal(directoryPath); } return true; } catch (error) { console.error('❌ 打开目录失败:', error.message); return false; } } /** * 使用示例 */ async function main() { // 示例1: 打开当前脚本所在目录 const currentFile = __filename; console.log('当前文件:', currentFile); // 方法1: 在文件管理器中打开 console.log('\n--- 在文件管理器中打开 ---'); await openFileDirectory(currentFile); // 等待2秒 await new Promise(resolve => setTimeout(resolve, 2000)); // 方法2: 在终端中打开(可选) console.log('\n--- 在终端中打开 ---'); await openFileDirectory(currentFile, { openInTerminal: true }); } // 命令行使用方式 if (require.main === module) { const args = process.argv.slice(2); if (args.length === 0) { // 没有参数,打开当前目录 openFileDirectory(process.cwd()) .then(success => { if (!success) process.exit(1); }) .catch(error => { console.error('错误:', error.message); process.exit(1); }); } else { const filePath = path.resolve(args[0]); const options = { openInTerminal: args.includes('--terminal') || args.includes('-t'), createIfNotExists: args.includes('--create') || args.includes('-c') }; openFileDirectory(filePath, options) .then(success => { if (!success) process.exit(1); }) .catch(error => { console.error('错误:', error.message); process.exit(1); }); } } // 导出函数 module.exports = { openFileDirectory, openDirectoryInTerminal, openTerminalInDirectory, getOSPlatform };