Home > Web Front-end > JS Tutorial > Working with the File System in Deno

Working with the File System in Deno

Jennifer Aniston
Release: 2025-02-09 09:43:10
Original
901 people have browsed it

Working with the File System in Deno

This article will dive into Deno and create a command line tool for searching for text in files and folders. We will use various API methods provided by Deno to read and write to the file system.

In the previous article, we built a command line tool using Deno to make requests to third-party APIs. In this article, we will temporarily ignore network operations and build a tool that allows you to search for text in files and folders within the current directory - tools like grep.

Note: The tools we build are not as optimized and efficient as grep, and we are not aiming to replace it! The purpose of building such a tool is to be familiar with Deno's file system API.

Key Points

  • Deno's file system API helps create command-line tools for searching for text in files and directories, similar to grep tools, but not as optimized.
  • Using Yargs in Deno, developers can build user interfaces for command-line applications, allowing text searches in specified directories.
  • Deno provides built-in functions such as Deno.readDir for listing files and Deno.readTextFile for reading file contents, thus simplifying file system interaction without additional imports.
  • You can use Deno's path module to efficiently manage file paths, which includes functions such as path.join to connect file paths.
  • Deno scripts require explicit permission flags, such as –allow-read or –allow-write to perform file system operations, which enhances security by controlling script functions.
  • Developers can use deno compile to compile Deno scripts into separate executables, simplifying distribution and execution by encapsulating the necessary permissions.

Installation Deno

We assume that you have Deno running on your local machine. You can check out the Deno website or the previous article for more detailed installation instructions and information on how to add Deno support to your editor.

At the time of writing, the latest stable version of Deno is 1.10.2, which is the version I use in this article.

For reference, you can find the full code for this article on GitHub.

Set new commands with Yargs

As in the previous post, we will use Yargs to build interfaces that users can use to execute our tools. Let's create index.ts and fill it with the following:

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);
Copy after login
Copy after login
Copy after login

There are a lot to point out here:

  • We install Yargs by pointing to the path in the Deno repository. I explicitly use the exact version number to make sure we always get that version so we don't use any latest versions when the script is running.
  • At the time of writing, Deno TypeScript has not had a good experience with Yargs, so I created my own interface and used it to provide some type safety.
  • UserArguments contains all the input we will request from the user. Currently, we only ask for text input, but in the future we can expand it to provide a list of files to search, rather than assuming the current directory.

We can run it with deno run index.ts and see our Yargs output:

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);
Copy after login
Copy after login
Copy after login

It's time to start implementing it!

List the file

Before we start searching for text in a given file, we need to generate a directory and list of files to search for. Deno provides Deno.readdir, which is part of the "built-in" library, which means you don't have to import it. It is available in the global namespace.

Deno.readdir is asynchronous and returns a list of files and folders in the current directory. It returns these items as AsyncIterator, which means we have to use for await ... of loop to get the result:

$ 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
Copy after login

This code will read and record each result from the current working directory (provided by Deno.cwd()). However, if you try to run the script now, you will receive an error:

for await (const fileOrFolder of Deno.readDir(Deno.cwd())) {
  console.log(fileOrFolder);
}
Copy after login

Remember that Deno requires that all scripts explicitly obtain permissions to read from the file system. In our case, the --allow-read flag will enable our code to run:

$ 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
Copy after login

In this case, I run the script in the directory of the build tool, so it finds the TS source code, the .git repository, and the .vscode folder. Let's start writing some functions to recursively navigate this structure, because we need to find all the files in the directory, not just the top-level files. Additionally, we can add some common ignores. I don't think anyone would want the script to search the entire .git folder!

In the following code, we create the getFilesList function, which takes a directory and returns all files in that directory. If a directory is encountered, it will recursively call itself to find any nested files and return the result:

~/$ 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 }
Copy after login

Then we can use it like this:

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;
}
Copy after login

We also get some output that looks good:

const files = await getFilesList(Deno.cwd());
console.log(files);
Copy after login

Using the path module

We can now combine file paths using template strings as follows:

$ 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"
]
Copy after login

But this would be better with Deno's path module. This module is one of the modules Deno offers as part of its standard library (very similar to Node using its path module), and if you have used Node's path module, the code looks very similar. At the time of writing, the latest standard library version provided by Deno is 0.97.0, we import the path module from the mod.ts file:

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);
Copy after login
Copy after login
Copy after login

mod.ts is always the entry point when importing Deno's standard modules. The documentation for this module is located on the Deno website and lists path.join, which will take multiple paths and join them into one path. Let's import and use the functions instead of combining them manually:

...(The rest of the code is omitted here because it is repeated with the original text and has been modified and optimized in the previous output.)

...(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.)

: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

The above is the detailed content of Working with the File System in Deno. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template