Check out a free preview of the full Introduction to Node.js, v3 course

The "FS Module" Lesson is part of the full, Introduction to Node.js, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Scott demonstrates how to use the built-in FS module, which provides an API for interacting with the file system. Student questions regarding debugging errors involving nesting callbacks are also covered in this segment.


Transcript from the "FS Module" Lesson

>> Let's talk about the fs module. So, fs module we've been hinting at it, I've used it in examples, but what is it? Fs stands for file system. It's a module that's built into node, so it's a core module, and it basically just gives us an API to interact with files.

I mean, at the end of the day, that's really what it does. So I know I've talked about it earlier, but literally anything you can do with a file, this thing can do programmatically, which I think is quite powerful. And on the surface, it doesn't seem like it but I'm telling you, the more you think about how every app in the world is just writing to files, you're like, wow, okay, I can make a database with this if I wanted to.

If you were some computer scientist who was studying databases for your thesis, you would probably use the fs module to make your database, it's quite powerful, you can do some really interesting stuff here. So, here's some of the frequently used methods, and we'll go over them, and we'll test them out, but you got mkdirl, that might sound familiar if you're on Linux or Mac or anything like that.

It's to make a directory, it's to make a folder. readdir, that's exactly what it sounds like, it's to read the directory. Stat to get information about a file. Unlink, delete a file, rename or rename a file. And then, of course, we got our two favorites, which are to read file and write a file.

So we're gonna talk about those, let's do that, let's play with some files here. So the first thing is, I'm gonna import fs from fs, and again, this is just me giving examples scratch code, it's not contributing towards our notes right now. So if you want to follow along, please do, but you can also just watch.

And I'm going to use this convention to be explicit, I'm gonna say node because it's a core module. Again, I don't have to, it's just I want to. I know for sure there's a module on npm called fs, I don't know why they did it, but I'm gonna use node here.

So we have fs. So now let's say I want to read a file, let's read this package.json, so let's do that. So I can say const, let's just say read. Pjson like this. So I'm gonna make a function that does that, and basically all it's going to do is it's going to try to read this package.json right here, it looks like my co-pilot is trying to tell me that this all it needs to do.

I actually don't think that's gonna work, I think we actually have to create a new url here. Or I'm gonna say like pjsonPath is a new url like this, oops, and we want to do this package.json, import.meta.pathname. So what the hell is this? Okay, in this latest version of Node.js, because we're using type module, we don't get access to this global that node used to have, which is called __dir name.

Which will give you the current directory in which you're working in. In fact, to recreate it I had to write this code right here that it's suggesting, and when we pass something to read file, we have to give it. We can't pass in just like a relative file like that, we have to give it kind of like an absolute path.

So we have to construct that, so that's what I'm doing. I construct that path and now I'm gonna pass it in here. Another thing to note is that I'm using something called readFileSync. This is the synchronous version of reading a file. So this will be a blocking function, which means nothing will happen until after this file is read.

You probably don't want to do this. Imagine if you had a server that was getting 100,000 requests per second and there was one route that read a file. Okay, every other request would have to wait until that one request read the file cuz it's synchronous. So you probably don't wanna do this.

So instead, you would wanna do the async version, which by default is just readFile. But that's gross because it takes a callback. I don't wanna do a callback, who wants to do that? So instead, I'm gonna use the promise version, Of fs that Node.js thoughtfully made for us.

So we can just do /promises and we get a promise version. So now, I can just do, await, right there, put an async here, and we're good. Pretty powerful, all right. Well, let's see what we broke cuz who knows if this is gonna work? So I'm going to run this, and let's see what happens on our test file, here we go.

So url is not defined, I think it's you url, that's why. Cool, I'm not logging anything, I'm like, why did I not do it? Let's console.log this. Okay, there we go, so it worked. It read the package.json file, it parsed the JSON and turned it into an object so then it logged it, right?

So it can read any file, it doesn't matter what the file is, it can read the contents of it. You can read a binary file, can read an image file, it'll just read it. So that's readFile, it's quite powerful, let's talk about writing a file. So let's write a file, And let's just say, we'll do something similar here, we'll copy this path.

And we'll call it a newFile path, and we'll call this, let's write some JavaScript, right, so demo.js. We'll write some JavaScript here, and then we can say, await fs.writeFile, make sure we put async here. And we wanna write to this new file path, and we wanna write some JavaScript.

So I'm gonna put a string in here and I'm gonna say console.log('yoooo!'), okay? So we're gonna write some JavaScript here. Then I'm gonna call this function like so, I'm gonna call this function, it should write the file with the JavaScript in it and then we're gonna execute that file, all in one command, all right?

So now I can go down here, I can say node test, which will call this file, which we'll write to the demo js file a console.log, and then when that's done, I then want to run demo.js, assuming it got created. So putting a double ampersand here means run this command, and then when it's done, run this command.

So this is like asyncawait in the terminal, basically. If I do one ampersand, it'll run them at the same time. This means run it after each other. So assuming test.js creates demo js, this should work, and it did, right? So we can go check that out. There we go, we have demo.js, it has a console.log in it and then we executed it, right?

So quite powerful of what you can do with the file system, you can automate. I actually have a lot of automations that I do on my personal life with just a bunch of node scripts that interact with files cuz it's just super powerful. I have e-mail templates and stuff like, I'm telling you, it's insane.

So yeah, any questions on this stuff?
>> Regarding the asynchronous code and callback hell situations. Is there a way to debug where a callback situation starts if maybe nested down a couple of modules to figure out where that callback hell sort of began, it's not all in one file or the same module?

>> Yeah, so, I'm biased because my debugging process is I just log everything. [LAUGH]. I don't use debuggers or anything like that, I'm not gonna say I've never had to, I definitely could have benefited from using debuggers, and sometimes I do. But for the most part, I think it's less about a tool in which you can use to help you find that, it's more about a process in which you can find it yourself.

And I think the process is basically, at least the way I think about it is, first off, if you have that many levels of abstraction, that might be a problem on its own where it's like you don't even know where something is being called, that's a lot of abstractions happening.

So that's one. That's what frameworks are for. So probably use a framework that handles those abstractions for you, and then two, basically, what I would do is you start at the most inner. So in this case, the most inner would be right where I am calling writeFile, right?

FswriteFile. This is not my code, this is a third-party module. So I don't know what's happening in there, and if that breaks, I actually don't care because I can't fix it. So I'll have to find something else, so I don't care if that breaks. So I would just start here, and I would immediately see what is the thing that I wrote after that.

And then I would check that and I would just move outward with logs, and I think the mindset you have to have is like you need an expectation on what you think is gonna happen and then you need to see what actually happens. And if those two things don't match, either you just expected the wrong thing or the computer's doing the wrong thing.

90% of the time it's probably you expected the wrong thing. The computer probably does exactly what you told it to do, you just told it the wrong thing. So that's kind of how I do it. And after three or four logs you'll find it, to actually prevent that if I'm doing something new where I don't really know what I'm doing.

And I think there might be errors here, I actually don't move on to the next line until I log everything before it to make sure that, it's like a bookmark. It's like, I know I've logged everything before this and it's exactly what I expected it to be, so if the next thing breaks, I know it's the next thing, and it was nothing before this.

So that's kind of like how I write code and uncharted territory where I'm not sure what the hell this thing is doing. So I don't end up in this state of like, I'm 12 levels deep and it can be anywhere. But given the case where you go join a company where that's already there, yeah, you just got to go find where the innermost call is being made and move outward, is where I would start.

You can also use the node debugger, but it's the same thing. The node debugger you're still gonna have to figure out what break point to put where and then move outward. There's no way around it, so I just use logs. All right, so we all know how to use files now, and there's so many of them.

Node.js docs, just watch this, I'm just gonna click on Files here. Let's see, where's fs? Okay, just look, look at all these methods, it just keeps going. AppendFile, copyFile, else it just keeps going, realPath, rename, remove, remove directory, stack. So there's a thing for anything, so you can get pretty crazy in here, so yeah.

It's still going, okay, there we go, there's a lot going on there. But the ones I showed you read and write pretty much most of stuff you'll do. And also there's a lot of third-party modules that take, some of the use cases that you would do with files.

And just make them functions for you, so like doing it raw like I need to check this directory or like, I had a use case where I was dynamically generating routes based off file names that you created. So I would recursively go through a directory so that way when you made a new file it would just make a route for you, so you have to do that yourself, and having to set that up with fs myself was very tedious and error prone.

So then I found this function on this package on npm that literally read files recursively and that was done, so I'll just use that. So there's a ton of stuff out there if you don't wanna do it manually.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now