本文將深入探討Deno,並創建一個命令行工具,用於在文件和文件夾中搜索文本。我們將使用Deno提供的各種API方法來讀取和寫入文件系統。
上一篇文章中,我們使用Deno構建了一個命令行工具,用於向第三方API發出請求。本文中,我們將暫時忽略網絡操作,構建一個工具,允許您在當前目錄內的文件和文件夾中搜索文本——類似於grep之類的工具。
注意:我們構建的工具不會像grep那樣優化和高效,我們也並非旨在取代它!構建這樣一個工具的目的是為了熟悉Deno的文件系統API。
Deno.readDir
用於列出文件和Deno.readTextFile
用於讀取文件內容,從而簡化文件系統交互,無需額外導入。 path.join
等函數,用於連接文件路徑。 –allow-read
或–allow-write
才能執行文件系統操作,通過控制腳本功能來增強安全性。 deno compile
將Deno腳本編譯成獨立的可執行文件,通過封裝必要的權限來簡化分發和執行。 我們假設您已經在本地機器上運行了Deno。您可以查看Deno網站或上一篇文章,以獲取更詳細的安裝說明,以及如何為您的編輯器添加Deno支持的信息。
在撰寫本文時,Deno的最新穩定版本是1.10.2,這就是我在本文中使用的版本。
作為參考,您可以在GitHub上找到本文的完整代碼。
與上一篇文章一樣,我們將使用Yargs來構建用戶可以用來執行我們工具的界面。讓我們創建index.ts並用以下內容填充它:
<code class="language-typescript">import yargs from "https://deno.land/x/yargs@v17.0.1-deno/deno.ts"; interface Yargs<argvreturntype></argvreturntype> { describe: (param: string, description: string) => Yargs<argvreturntype>; </argvreturntype> demandOption: (required: string[]) => Yargs<argvreturntype>; </argvreturntype> argv: ArgvReturnType; } interface UserArguments { text: string; } const userArguments: UserArguments = (yargs(Deno.args) as unknown as Yargs<userarguments>) </userarguments> .describe("text", "the text to search for within the current directory") .demandOption(["text"]) .argv; console.log(userArguments); </code>
這裡有很多值得指出的內容:
我們可以使用deno run index.ts運行它並查看我們的Yargs輸出:
<code class="language-typescript">import yargs from "https://deno.land/x/yargs@v17.0.1-deno/deno.ts"; interface Yargs<argvreturntype></argvreturntype> { describe: (param: string, description: string) => Yargs<argvreturntype>; </argvreturntype> demandOption: (required: string[]) => Yargs<argvreturntype>; </argvreturntype> argv: ArgvReturnType; } interface UserArguments { text: string; } const userArguments: UserArguments = (yargs(Deno.args) as unknown as Yargs<userarguments>) </userarguments> .describe("text", "the text to search for within the current directory") .demandOption(["text"]) .argv; console.log(userArguments); </code>
現在是時候開始實現了!
在我們開始搜索給定文件中的文本之前,我們需要生成一個要搜索的目錄和文件列表。 Deno提供Deno.readdir,它是“內置”庫的一部分,這意味著您不必導入它。它在全局命名空間中可用。
Deno.readdir是異步的,並返回當前目錄中文件和文件夾的列表。它將這些項目作為AsyncIterator返回,這意味著我們必須使用for await ... of循環來獲取結果:
<code class="language-bash">$ deno run index.ts Check file:///home/jack/git/deno-file-search/index.ts Options: --help Show help [boolean] --version Show version number [boolean] --text the text to search for within the current directory [required] Missing required argument: text</code>
這段代碼將從當前工作目錄(Deno.cwd()提供)讀取並記錄每個結果。但是,如果您現在嘗試運行腳本,您將收到錯誤:
<code class="language-typescript">for await (const fileOrFolder of Deno.readDir(Deno.cwd())) { console.log(fileOrFolder); } </code>
請記住,Deno要求所有腳本都明確地獲得從文件系統讀取的權限。在我們的例子中,--allow-read
標誌將使我們的代碼能夠運行:
<code class="language-bash">$ deno run index.ts --text='foo' error: Uncaught PermissionDenied: Requires read access to <cwd>, run again with the --allow-read flag </cwd>for await (const fileOrFolder of Deno.readDir(Deno.cwd())) { ^ at deno:core/core.js:86:46 at unwrapOpResult (deno:core/core.js:106:13) at Object.opSync (deno:core/core.js:120:12) at Object.cwd (deno:runtime/js/30_fs.js:57:17) at file:///home/jack/git/deno-file-search/index.ts:19:52</code>
在本例中,我在構建工具的目錄中運行腳本,因此它找到了TS源代碼、.git存儲庫和.vscode文件夾。讓我們開始編寫一些函數來遞歸地導航此結構,因為我們需要找到目錄中的所有文件,而不僅僅是頂級文件。此外,我們可以添加一些常見的忽略項。我認為沒有人會希望腳本搜索整個.git文件夾!
在下面的代碼中,我們創建了getFilesList函數,它接受一個目錄並返回該目錄中的所有文件。如果遇到目錄,它將遞歸調用自身以查找任何嵌套的文件,並返回結果:
<code class="language-bash">~/$ deno run --allow-read index.ts --text='foo' { name: ".git", isFile: false, isDirectory: true, isSymlink: false } { name: ".vscode", isFile: false, isDirectory: true, isSymlink: false } { name: "index.ts", isFile: true, isDirectory: false, isSymlink: false } </code>
然後我們可以像這樣使用它:
<code class="language-typescript">const IGNORED_DIRECTORIES = new Set([".git"]); async function getFilesList( directory: string, ): Promise<string> { const foundFiles: string[] = []; for await (const fileOrFolder of Deno.readDir(directory)) { if (fileOrFolder.isDirectory) { if (IGNORED_DIRECTORIES.has(fileOrFolder.name)) { // Skip this folder, it's in the ignore list. continue; } // If it's not ignored, recurse and search this folder for files. const nestedFiles = await getFilesList( path.join(directory, fileOrFolder.name), ); foundFiles.push(...nestedFiles); } else { // We found a file, so store it. foundFiles.push(path.join(directory, fileOrFolder.name)); } } return foundFiles; } </string></code>
我們還得到一些看起來不錯的輸出:
<code class="language-typescript">const files = await getFilesList(Deno.cwd()); console.log(files); </code>
我們現在可以使用模板字符串組合文件路徑,如下所示:
<code class="language-bash">$ deno run --allow-read index.ts --text='foo' [ "/home/jack/git/deno-file-search/.vscode/settings.json", "/home/jack/git/deno-file-search/index.ts" ] </code>
但這使用Deno的path模塊會更好。此模塊是Deno作為其標準庫一部分提供的模塊之一(與Node使用其path模塊非常相似),如果您使用過Node的path模塊,則代碼看起來非常相似。在撰寫本文時,Deno提供的最新標準庫版本是0.97.0,我們從mod.ts文件導入path模塊:
<code class="language-typescript">import yargs from "https://deno.land/x/yargs@v17.0.1-deno/deno.ts"; interface Yargs<argvreturntype></argvreturntype> { describe: (param: string, description: string) => Yargs<argvreturntype>; </argvreturntype> demandOption: (required: string[]) => Yargs<argvreturntype>; </argvreturntype> argv: ArgvReturnType; } interface UserArguments { text: string; } const userArguments: UserArguments = (yargs(Deno.args) as unknown as Yargs<userarguments>) </userarguments> .describe("text", "the text to search for within the current directory") .demandOption(["text"]) .argv; console.log(userArguments); </code>
mod.ts在導入Deno的標準模塊時始終是入口點。此模塊的文檔位於Deno網站上,並列出了path.join,它將接受多個路徑並將它們連接成一個路徑。讓我們導入並使用該函數,而不是手動組合它們:
...(此處省略了其餘代碼,因為與原文重複,並且已經在上一個輸出中進行了修改和優化。)
...(The rest of the code is omitted because it's repetitive from the original and has already been modified and optimized in the previous output.)
以上是在DENO中使用文件系統的詳細內容。更多資訊請關注PHP中文網其他相關文章!