VSCode扩展开发:如何用相对路径读取同目录文本文件?
我正在开发一款VSCode扩展,调用encloseTag命令时,会从文本文件加载预设标签列表,将选中文本包裹在选中标签中。目前仅指定静态路径时可正常运行,使用相对路径则报错:
Error reading tags file: ENOENT: no such file or directory, open 'tags.txt'
Activating extension 'undefined_publisher.enclosingtags' failed: ENOENT: no such file or directory, open 'c:\Users\username\ProjectPublisher\out\FILENAME'.
打印工作目录后发现,其并非项目目录(位于AppData而非用户文件夹中的项目位置)。我是通过VSCode按F5调试运行扩展的,请问如何让代码读取与extension.ts同目录的tags.txt文件?
相关代码
package.json
(…) "contributes": { "commands": [ { "command": "encloseTag", "title": "Enclose in Tag" } ] }, (…)
extension.ts
import * as vscode from 'vscode'; import * as fs from 'fs'; export function activate(context: vscode.ExtensionContext) { let disposable = vscode.commands.registerCommand('encloseTag', () => { let editor = vscode.window.activeTextEditor; if (!editor) { vscode.window.showErrorMessage('No active text editor'); return; } let selection = editor.selection; let text = editor.document.getText(selection); if (!text) { return; } let tags: string[] = []; try { let data = fs.readFileSync('C:\\Users\\username\\ProjectPublisher\\tags.txt', 'utf8'); // Split the data into lines and remove leading and trailing whitespace and newline characters from each line tags = data.split('\n').map(line => line.trim().replace(/\r?\n|\r/g, '')); } catch (error: any) { vscode.window.showErrorMessage('Error reading tags file: ' + error.message); return; } // Prompt the user to select a tag vscode.window.showQuickPick(tags).then((tag) => { if (!tag) { return; } // Enclose the selected text in the chosen tag let newText = `<${tag}>${text}</${tag}>`; editor.edit(edit => { edit.replace(selection, newText); }); }); }); context.subscriptions.push(disposable); const fs = require('fs'); fs.readFileSync(`${__dirname}\\FILENAME`); } export function deactivate() {}
tags.txt
tag1 tag2 tag3
核心问题是VSCode扩展调试时的工作目录并非项目源码目录,而是编译后的out目录或临时运行目录,直接用相对路径会找不到文件。要读取和extension.ts同目录的文件,需通过VSCode扩展上下文获取正确路径,步骤如下:
利用
context.extensionPath获取扩展根目录context.extensionPath是VSCode提供的上下文属性,会返回扩展项目的根目录路径,调试和发布状态下都能正确获取。用
path模块拼接文件路径
借助Node.js的path模块拼接路径,自动处理跨平台路径分隔符差异,避免手动拼接出错。
修改后的extension.ts关键代码:
import * as vscode from 'vscode'; import * as fs from 'fs'; import * as path from 'path'; // 新增导入path模块 export function activate(context: vscode.ExtensionContext) { let disposable = vscode.commands.registerCommand('encloseTag', () => { // 保留原有编辑器检查、选中文本获取的代码 let tags: string[] = []; try { // 拼接tags.txt的完整路径 const tagsFilePath = path.join(context.extensionPath, 'tags.txt'); let data = fs.readFileSync(tagsFilePath, 'utf8'); tags = data.split('\n').map(line => line.trim().replace(/\r?\n|\r/g, '')); } catch (error: any) { vscode.window.showErrorMessage('Error reading tags file: ' + error.message); return; } // 保留后续选择标签、替换文本的代码 }); context.subscriptions.push(disposable); // 读取其他同目录文件的示例 const testFilePath = path.join(context.extensionPath, 'FILENAME'); fs.readFileSync(testFilePath); }
- 确保
tags.txt被打包进扩展
在package.json中添加files字段,确保非代码文件被包含在扩展包中:
{ "files": [ "out/**/*.js", "tags.txt" // 新增该行 ] }
说明
context.extensionPath:始终指向扩展的根目录,调试时是项目源码目录,发布后是扩展安装目录。path.join():自动适配Windows和Linux的路径分隔符,避免手动书写分隔符导致的兼容性问题。files字段:确保tags.txt这类资源文件被包含在扩展包内,否则调试或安装后会出现文件缺失错误。
内容的提问来源于stack exchange,提问作者MrVocabulary

