HOW TO SEARCH FOR FILES WITH USER-INPUT (Node.js)
Tags: javascript, programming, node, webdev
Published: 2022-02-01 00:39:25

**Node.js is an event-driven, JavaScript runtime which can
perform operations asynchronously in a such a way that is non-blocking in execution sense. These operations could include: FS/IO, HTTP operations etc. Node wraps the JavaScript language with extra rich features which enables the language perform operations that it can't do by default such as: reading and writing to files locally, running a full-fledged end-to-end network communication; as JavaScript's scope of operation is limited to the browser window. Hence, Node can allow us run JavaScript in environments other than the restricting interface of the browser.**

In this article we will see **how to search for existing files** within a local directory via user-input in Node. At the end of this article, you should be familiar with the node and its  
`fs` and `readline` modules and how to use its associated methods to find existing files in our directory.

### Setup:

First off, we auto create a `package.json` file that will help us manage our dependencies and other things such as versioning in the future. 
So on your terminallocked in on the root of the project directory, type the code: 
`npm init –y` or `yarn init -y`
This generates the package file. So, we can now install npm packages such as **nodemon** which refreshes our node sessions each time we make and save a change to our files. 
Finally, we would update the **package.json** file by adding a `type: "module"` field to the file. This would enable us use the more modern and elegant ES2015(ES6) syntax in our node project(_this is optional, as you could choose to use commonjs `require` syntax_). Exciting huh ?
Finally, we create an index.js file where we will write and test all our code.

To serve as our dummy files to be read, we would create a folder called **blogs** in our projects directory, there we will create three(3) text files - (_text1.txt, text2.txt, text3.txt_), and for each of these files we populate them with our preferred dummy data- `Lorem Ipsum!`
You could also use a more meaningful data for this, its your choice. Your folder structure, and `package.json` file should be looking similar to mine below:


![package.json](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mazih3muy2yejikr1fl1.png)

```
{
  "name": "Nodescratch",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type": "module",
  "scripts": {
  "start": "nodemon index.js"
},
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "nodemon": "2.0.2"
  }
}
```

### Ok, back to Node:

Nodejs has a couple of built-in core modules that can be used for various important operations, these includes: **HTTP**, **Events**, **FS**, etc. We would be working with the FS module (_FS stands for File System; quite self-explanatory if you ask me_ ).
The FS module has some important helper methods that we can use to make manipulations on both local files on our machine and _beyond_. For this article, we would import and use three of these methods `readFile`, `readdir`, also we would import another
method from the **readline** module called `readline`. This module allows us to read/accept data from the user via an interface:

```
import readline from "readline";
import { readFile, readdir } from "fs";
const { log, error } = await import('console') /* this is to avoid typing console.log or console.error redundantly */

```

To get users input, we would be using the `readline` method which provides an interface for reading data from a readable stream, the most common being –
`process.stdin`. 
This operation takes some time to complete and hence traditionally
we would often use a callback function to handle the response once it’s done, but we would be making our codes more Promise-based by using the `promisify` method of nodes _community module_ called `util` (_I would definitely talk about that in depth in another article_). So, lets how that is used in code:

```
import readline from "readline";
import { readFile, readdir } from "fs";
const { log, error } = await import('console')

import util from "util";
const rFile = util.promisify(readFile);
const rDir = util.promisify(readdir);
```

The `readFile` asynchronously reads the entire contents of any file. This method takes two arguments, the relative path to the file and a callback function to handle response. But we would be using a rather modern approach by transforming this method to Promise-based method like the one above using `promisify`.
Inclusively, the `readdir` method can read the contents of a directory (folder) and just like the `readFile` method, `readdir` takes two arguments: a relative path to the
directory and a callback. Just like before, we would `promisify` this method.
Doing this enables us to elegantly use these methods with the `await` keyword in an `async` function as depicted below:

```
import readline from "readline";
import { readFile, readdir } from "fs";
const { log, error } = await import('console')
import util from "util";

const rFile = util.promisify(readFile);
const rDir = util.promisify(readdir);
async function get() {
    try {
        const file = await rDir("./blogs");
        setTimeout(() => log("Available files are:",file),3000);
    } catch (e) { error(e.message);}
}

```

Another function we would define is the search function which would listen to our inputs, formats its and make search operations asynchronously based on this input.
But before we define this function, we need to create an interface that would let us key in inputs and also get outputs logged to the console. This function would be called later when we define an interface for accepting user input. Lets look at how the function is defined:

```
async function search(userInput) {
  try {
    const data = await rFile(`${userInput}`);
    log(data.toString());
  } catch (e) {
    error(e.message);
  }
}
```

Finally, we should note that the `question` method of the `readline` can be used to throw a query or question a user to perform an input operation. It should also have a callback function that grabs the input and runs an operation using the input as a payload; thus when called, `rl.question()` will resume the input stream if it has been paused.
Note, the callback passed to `rl.question` does not follow the typical pattern of accepting an ‘_err & data_’ as arguments, rather it’s called with the provided answer (_user-input_) as the only argument. Lets see how that’s done:

```
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});
rl.question("Search for a file..\n", (input) => {
  const userInput = input.trim();
  search(userInput); // the 'search function is called at this point
  get(); // the 'get function is called after the search
  log(`You searched for ${userInput}`);
  rl.close();
});
rl.on("close", () => {
  log("Searching....");
});

```
To execute this file and get our data using our input, open the Terminal, using the node runtime we would execute the module by typing - `node index.js`. 
We would get a prompt that tells us to `Search for a file… `.
Enter the keywords - `blogs/text1.txt`, which is the name of the dummy files we created earlier (_Don’t forget to include the .txt extension_).
And we should get a satisfactory result of - 

```
You searched for blogs/text1.txt
Searching....
// data is output after some secs.
```
After a moment you should get your file served to you beautifully on the Terminal, hurray.

### Summary:

Now, let’s have a summary of everything we’ve done so far. All we did was use a fancy syntax to get our users input via the `readline` interface. A function is executed that uses the `readFile` and `readdir` method to search for and beautifully return our files content on the Terminal.

If you made it to the end of this article, Congrats! Now you have a task of making this even more better and elegant than I could.
Keep learning, keep discovering and keep sharing.

Ping my Twitter handle when you can- [Patrick](www.twitter.com/mod5ied)