The course is part of this learning path
This course covers file input/output (file I/O). Being able to read from and write to secondary storage is important because often we want to keep some data persistently. By the end of this course, you will have the skills necessary to do this.
- Understand the fundamentals of both file input and file output and how to use both in tandem
- Use stream manipulators to make the structure of the data more organized
- Use dynamic memory, pointers, and classes to make more complex and interesting applications
- Beginner coders, new to C++
- Developers looking to upskill by adding C++ to their CV
- College students and anyone studying C++
To get the most out of this course, you should have a basic understanding of the fundamentals of C++.
In the previous lecture, you worked on a project to really dive into the fundamentals learned in this section. In this lecture, you will work on another project. This time you will use the same Rectangle class that we originally developed in the section on classes and OOP. The class files along with a text file, rectangles.txt, will be provided as resources with this lecture. You will create a project called DynamicFileRectangle. The file for input will contain on each line, two integers, the length followed by the width, with a space in between. So, each line in the file represents a single rectangle. I'd like you to read in the data from the file and as you do, dynamically create rectangles, storing them in a vector of Rectangle pointers. When you are done reading them in, I'd like you to print to an output file, the perimeters and areas of each of the rectangles. For my implementation, I broke some of the tasks like populating the vector from file, printing the areas and perimeters to an output file, and releasing the allocated Rectangle memory, and clearing the vector into functions. You may try solving this problem however you would like. Make sure to delete the Rectangle objects when done. All right, let's check out the dynamic file Rectangle project to see what it looks like when we run it. Debug, start without debugging. Don't really see anything on the console, but if we go to file, you can see that there is an output file and that it has perimeters and areas written to it. So, that's what we should get. Hope that helps. So, pause the video and when you're done come back and see how I would do it. So, how did this little experiment go for you? Were you able to complete it? This one really stretches your skills quite a bit and combines a lot of what we've worked on throughout the course. Let's work on it together. So, first we'll create the Dynamic file Rectangle project. Empty Project; DynamicFileRectangle, hit 'Create'. And we have some things that we need to copy over. So, I've got my repos and my files that were resources. So, DynamicFileRectangle is right here and then the project folder is there. So, we have the text file, the Rectangle.h and Rectangle.cpp. I'm going to copy those and paste them over here. Alright, should be good. Now I do need to add the .h and the .cpp file to our project. So, I'll add them both to the headers and then move around as necessary. So, add existing items and it will look underneath the project folder. So, I will grab both of these Rectangle.cpp and Rectangle.h, add them and then move the cpp file down to source files. This is the same Rectangle that we've worked with before, nothing new, nothing special. I'm going to right click 'Source files' and create a main.cpp right here. All ready. Include iostream, include fstream, got a lot to use here. Include vector, we need that and then of course, include Rectangle.h using namespace standard. And then of course we've got int main. There's our skeleton. And I told you that I broke up my solution and we're going to do that here. So, I have populateVector. Well that's populating it from an input file stream and I could open it from within populate vector if I wanted to but I decided to pass it in, as a reference if stream is a class, so I can use it this way. And I'm going to pass in a vector of Rectangle pointers reference called rectVector. I also need printData that takes an ofstream outfile right there, takes Rectangle pointer vector, also called rectVector. And then we have deallocateRectangles. A vector of Rectangle pointers, reference called rectVector. That one doesn't require a file, correct? Because all we're doing is we're going to be using it to release all of the objects that are pointed to by the stuff in the vector and then also clearing the vector itself using the clear method. So, I'm going to copy all these. Go below main. So, I got the prototypes and now I'm going to set up at least the definitions and this will help us keep main relatively clean. It'll still do work but this will help it a little bit. So, here's what I have in mind here. I guess we could... it doesn't really matter what order we do it. And so, let's say vector of Rectangle* we create in main, rectVector, we can call it whatever we want. It doesn't matter. Infile ofstream out file. We know that we have infile.open and we have the rectangles.txt and we have outfile.open, output.txt. And of course, you have the bookends, right? infile.close outfile.close. All right. Now it would be nice if we could make sure that the file is good here. So, if the file is not good, if we're not able to open it, Error opening file Bailing out endl return 1. Good. Now we need to call populateVector. So, if we know we have a good input file we'll pass in file and the rectVector into that. So, that will populate it. And we could print out maybe the size of the vector to know how many items are in it and then print the data. But I think I'm just going to print the data. So, printData outfile, rectVector. And then once it's done printing all of the data, we don't need the Rectangles anymore. We're not using them for anything else. So, we call deallocateRectangles. Awesome. So, that's all we have there. Now we have to actually work on the meat of the program which are in these three functions. Populate vector, I'm going to create a temporary Rectangle in length and width for input. The infile was already open so we don't have to open or close it in here. You actually shouldn't close the infile or try opening it because it's already been done inside of main, right? And then we call populateVector here. So we're just taking advantage of it and using it and actually reading the file. So, we know that there is a length and we could actually do this with two stream extraction operators in a row on the same line but I like keeping these nice and separate when it's just simple data like this and it will actually skip over the space because that's not an integer and it will know that those two are separate. So, each line, each time through this loop will represent a single line but it will pick up the length, space, width. Excellent. Now we use the temp pointer, we're going to say temp = new Rectangle based on the length and the width. And then we say rectVector.push_back because that's our vector and it's a vector of pointers to Rectangles. So, it just pushes them into the vector. So, you passed a vector in and passed an infile in and we get back a vector full of Rectangle pointers. Awesome. Now print data is also going to be used. For this one, I think, I'll just do this. I'll use the enhanced or range based for loop for each Rectangle pointer in the rectVector. So, we can do it this way; we're going to say outfile because that was passed in to rectPtr. We're going to call area right there and maybe a tab and then rectPtr perimeter and then endl. Good, that's all that does, it just prints the file. And we passed the file, told it what to do, when we call it printData up here, it passes outfile which represents the output.txt and also the rectVector which had been populated already previously and then deallocateRectangles. This is an important step because we have to manage the memory if we're using this type of pointer, these raw pointers. So, we're going to go through here for every one of the pointers in there delete, all right? And you could also set the rectPtr to know but it's really not really worth it because we're about to empty the vector now. So, you empty the vector afterwards. So, even though it has a bunch of dangling pointers in it, once you call rectVector.clear, all of those are gone. So, there's really no point in sending them to a null pointer. So, of course let's run it and also check out the file to make sure this works. If there's any errors or problems didn't get anything to the console. Let's go into the project and we do in fact have output.txt And, lo and behold, we have the perimeters and areas right here. So, pretty cool. You can look at the Rectangles.txt if you'd like, and look at them and make sure they make sense, right? Because we are printing the area, a tab and then the perimeter. So, each of these right here. you have the rectangles input and then the output. You've got this and then that. So, 12 x 20 x 2, 12 x 2 is 24, 10 x 4 is 40. And then you can look at the perimeters. That's interesting, both of those have 28. But it's two times is 20 2 x 4 is 8 so that's 28, 2 x 12 is 24, 2 x 2 is 4, that's 28 also, so that's what we got there. Same thing down there, pretty cool. Alright, so it looks pretty good to me. You can verify that yours works just as well. Make sure that everything looks good, if you've got some really weird numbers and it didn't seem to make sense, you know, try using maybe, instead of your own Rectangle.h and Rectangle.cpp, maybe there was a bug in it. So, you could try the ones that I have or if you created a different input file or using the wrong input file that can cause bugs, logic errors because it may not crash. It just looks kind of funny and things don't seem to be right. So, just make sure you check it out. So, awesome work everyone that that one was a bit of a challenge. So, you may have missed certain parts like clearing the vector. That's probably one of the more obvious ones. Or maybe even you forgot to delete the individual rectangles pointed to by the vector indices, right? So, that's totally okay though. You're getting better and better all the time. Watching me code and listening carefully, trying to follow along and reviewing when necessary is what will make you a stellar developer. Keep up the hard work. In the next lecture, you will work on another project for this section. This is a project where you will obtain data from a shopping list. I'll see you there.
John has a Ph.D. in Computer Science and is a professional software engineer and consultant, as well as a computer science university professor and department chair.