VS Code扩展:如何将工作区文件夹URI路径转换为文件系统路径?
问题场景
开发VS Code扩展时,需要用「文件>打开文件夹」选择的工作区路径作为Shell命令执行和fs.readdir()的基础目录。但直接使用vscode.workspace.workspaceFolders[0].uri.path会出现盘符重复的错误:
Error: ENOENT: no such file or directory, scandir 'C:\c:\Users\Dave\Desktop\ESP Labs'
发现私有属性uri._fsPath能得到正确路径,但不想依赖非公开API,求官方转换方法。
官方解决方案
有两种可靠的官方方法:
直接使用
uri.fsPath属性
VS Code的Uri对象提供了公开的fsPath属性,会直接返回适配当前操作系统的本地文件系统路径,无需手动转换。这是官方推荐的方式,完全替代私有_fsPath。正确使用Node.js的
url.fileURLToPath
之前用这个方法崩溃是因为传入了uri.path而非完整的file URL。需要传入uri.toString()得到的完整file URL字符串,比如file:///c%3A/Users/Dave/Desktop/ESP%20Labs,转换后就能得到正确的本地路径。
修正后的代码示例
替换原有路径获取逻辑,使用fsPath的版本:
/* * Copy entire project directory to remote flash file system. */ let syncCommand = vscode.commands.registerCommand('mpremote.sync', async () => { if (!vscode.workspace.workspaceFolders || vscode.workspace.workspaceFolders.length != 1) { vscode.window.showErrorMessage('Unable to sync. Open a folder first.') } else { const workspaceFolder = vscode.workspace.workspaceFolders[0]; console.debug('uri.fsPath:', workspaceFolder.uri.fsPath) let projectRoot = workspaceFolder.uri.fsPath; console.debug('Project folder path:', projectRoot) let port = await getDevicePort() term.sendText(`cd '${projectRoot}'`) fs.readdir(projectRoot, { withFileTypes: true }, (err, entries) => { if (err) { console.error(err) vscode.window.showErrorMessage('Unable to read directory.') } else { console.debug('Directory entries found:', entries.length) entries.forEach(entry => { console.debug('Examining directory entry:', entry) if (entry.isDirectory()) { if (SYNC_IGNORE.includes(entry.name)) { console.debug('Skipping directory:', entry.name) } else { term.sendText(`${PYTHON_BIN} -m mpremote connect ${port} fs cp -r ${entry.name} :`) } } else { term.sendText(`${PYTHON_BIN} -m mpremote connect ${port} fs cp ${entry.name} :`) } }) } }) } })
如果用url.fileURLToPath,则替换路径获取部分为:
const url = require('url'); // ... let projectRoot = url.fileURLToPath(workspaceFolder.uri.toString());
为什么uri.path不行?
uri.path是符合URI标准的路径格式,在Windows系统下会以/c:/开头(比如/c:/Users/Dave/Desktop/ESP Labs),直接传给Node.js的fs模块时,会被错误解析成C:\c:\...这种重复盘符的路径,导致找不到文件。
而uri.fsPath是VS Code内部处理后的结果,自动适配了Windows的盘符格式(c:\Users\...)和类Unix系统的绝对路径格式,完全符合fs模块的要求。
内容的提问来源于stack exchange,提问作者Dave H.

