Hello, and welcome back.
In this lecture, I'd like to talk about how we can
read text from a file.
For now, we're going to concentrate on reading text files.
So if we want to read character from a text file, we're going
to use a couple functions.
First one is going to be fgetc.
This will read a character from a text file that has been opened for reading.
Remember, we always have to open up the file before we can perform
any file operations on it unless it's a rename or a delete and
then the file cannot be opened.
But if you want to do reading and writing or appending,
we have to open that file.
We know that we can open up files with different modes.
In this case for reading, we'd have to open up with an r or an r plus,
and then we can start calling fgetc.
The fgetc function takes the file pointer as its only
argument, and it will return the character read as type int.
So here an example, we create an mchar type int, and we say fgetc pfile.
It's going to read a character into the mchar variable with
pfile as a file pointer.
Think of pfile already been opened return to file pointer.
The mchar is of type in because eof which is our special character
our end of file, that's returned if the end of file has been reached.
So we can always check that integer to see if it's eof.
And if it is, we don't want to read anymore,
we don't want to call fgetc anymore.
The function fgetc, which is equivalent to fgetc is also available.
So getc is almost the same as fgetc, you just want to use fgetc.
I think it has some more protection in it.
With getc, it requires an argument of type file star and returns
and returns the character red as type int.
It's virtually identical to fgetc.
The only difference between them is that getc may be implemented
as a macro, and we don't even know what a macro is now.
So we're going to stick with using fgetc as our function
to reading characters.
You can read the contents of a file.
Again, when necessary, you can use this rewind function which positions
the file that is specified by the file pointer to the beginning of the file.
So you can use rewind if you want to read again.
Just say rewind and then the file pointer, pretty basic.
So here's an example.
You have to include the standard io header whenever
we do any file operations.
In our main function, we're going to create our file pointer.
If I want to initialize this to null and we're going to create an integer.
First thing we're going to do is we're going to open up the file using the f
open call, and we're going to specify the name of the file and we're going
to specify that it's for reading.
That will return our file pointer.
So now our fp pointer is pointing to a valid file.
If it was unable to open file.txt that's not in the right path or
whatever, it's going to return null.
So you want to check for null, make sure fp is not null.
If it is null, exit the program.
Otherwise, when you usually read characters, you're going
to have them inside of a loop.
So here we're saying while c equals fgetc fp, this is reading
a character from our file, passing in the file pointer to fgetc,
which returns an integer.
Remember, we can jump out of the loop if that integer returned is the end
of the file because we don't want to read past the end of the file.
Otherwise, we can just print out our character using percent c and c.
Last thing we want to do is we want to close the file, we then
want to set our file pointer to null, and we can return.
Let's try utilizing this, creating this inside of code blocks.
Here's our program inside code blocks.
It says, this program's not going to work unless we have a file on disk
wherever the program is running.
So first if we build this, it should build okay, it
should create an executable somewhere on your hard drive.
I've been putting all of my projects inside my dot loans directory.
So if I go to my downloads directory and I go to the project
name, which this is just a test project so wherever you're storing
your projects mine's in test.
If I go to test, you'll see that inside the bin directory,
inside debug is your executable.
Here is where you create your file if you had a relative.
Path so here I could just create a new file and we can have it as a text
file so I can just create it as a text document, and it has to be named file.
And then I'm going to put some information in it.
I'm just going to put in some data such as hi this is Jason line feed.
Okay, nope, so forth, and I'm going to save it.
This file has to exist in order for this program to work.
So I created the file.
Now when I run it, hopefully it will read what I just
added to it and print it out.
It says error and file opening file no such file directory,
and that's probably because I have it in the debug folder.
And this is not running in debug.
So let's try running it in debug, and I think it would probably work now.
We can say debug, start.
This will look for the executable in the debug directory hopefully.
We want to make sure it's run.
Still not there, so you have to make sure you know where the executable is.
Let's try somewhere else or better yet I could just run
the executable inside the debug directory and should find it there.
So if I double click here, it actually um doesn't pause.
It jumps out.
So what you can do for that is instead of returning you can say
system pause and it won't exit the program until you've run it.
So let's now try it.
So now paused, didn't execute the program.
And what you saw was, hi this is Jason.
It was able to find the file, printed out okay, printed
out nope and then it paused.
Otherwise, when you execute the program, it prints the
data so fast and exits the program that you're done.
So that's how you can test it.
It must be stored where the executable is stored where it's running from.
It must be running from somewhere else in your project directory.
I'm not sure where it's running from.
We could try put moving the file to where the source code is.
It might be running it from here.
So here we'll put it in here.
And now we'll try running it from the ID and maybe it will work.
We don't build.
We run it, and it was able to find it.
So it looks like we have to put the file inside of
where the source code is.
So as long as we put that file file.text inside the project
file, you'll be able to see it.
So quick example of how you can open up a file and read single
characters, not the most efficient way to read from a file because
usually you want to read strings.
But this will open it up.
You see the f open call, and you notice the while loop.
That's important.
Let's go back and talk about how we can read strings from a file
which is much more efficient.
So that's reading a single character.
How about reading a string?
You can use the fgets function to read from any file or stream.
This will read a string.
It takes a character string has the first parameter.
The number of characters you want to read and then the actual file pointer.
So this function is going to read a string in the memory
area pointed by the str.
So you have to actually pass in the buffer where the
data is going to be stored.
And that's a pointer, so you'd have to allocate memory for it.
And then it's going to read from the file specified as the third
parameter which is the file pointer.
And then the nchar is going to say how much data to read.
So if you put nchars as like 10, it's going to read in 10 characters
unless it hits a line feed first.
So it's going to either read an entire line or it's going to read
the number of characters that you specify in the second parameter.
The end of line is specified by the backslash n whichever occurs first.
If a newline character is red, it's retained in the string
and a null terminator will be appended to the end of the string.
So if you actually specified more characters, it would read
up to the line feed, and then jump out and then it gets that
new line character and puts a null character at the end of it.
If there's no error, fgets is going to return the pointer,
which is the first parameter.
It's going to return a pointer which gets returned from the function.
And then it's also going to populate the str pointer
as the first parameter.
If there is an error null is returned.
And then reading the end of file causes null to be returned, that
means you read all of your strings.
So let's look at an example.
Here we have our main, and we're creating our file pointer
creating a character string.
Here this is a pointer we didn't mallocate any data for it, we
just create a character array.
We open up the file for reading, reading only because it's r.
We said if it's null, jump out.
Otherwise, we just say fgets, we read in 60 characters.
Or if the line feed is before that, a line feed will come up
and then it will print it out and what's ever in the str buffer.
So str is that first character that's passed in.
And then we close the file pointer, set it to null and return zero.
So let's, again, take a look at this inside of our code blocks IDE.
The only thing that's changed in this program is really lines 14 to 17.
We're using fgets to read our string in, and then we have a str buffer.
So we've also need to create a character array up here which is our
str, and we want this to contain 60.
We're reading in 60.
We'll add a line feed, so it's going to read in 59 and then add
a line feed to the end of it.
So we could say 61.
And then the fgets is going to be in an if statement, and it's going to
read in each string until it either hits 60 characters or a new line, and
it's going to print out that string.
You'll notice that's not a while loop, so we're not
reading to the end of the file.
We read the end of file, we get a null.
So if we build this, we want to make sure we have our quotes correctly.
Whenever you copy from powerpoint it messes up the quotes.
And we want to make sure we created our variable c
is not used that's okay.
So let's go ahead and run this.
And you see hi this is Jason.
So actually read in an entire line of text from the file.
It read in the first line.
So you would call it again and read in the second line.
If you change the number of bytes read, say we just want to read 10,
it would read in 10 and then it would return those 10 as opposed
to reading the entire line.
So here we just have it hi this I.
So it's going to read in number of characters your second
parameter or until it gets a line feed and it stores that in str.
Str is a character array.
We print it out fgets.
Fgets is a lot more efficient for reading.
Because we're not reading a character and at a time,
we're reading in more data.
Reading a character in a time is not as efficient.
So now we know how to read in single characters, we know how to read
in strings until they read a new line or a number of characters.
But you can also read in formatted input from a file.
So we have getc, fgetc, fgets.
And now we have another function called fscanf.
This is formatted input.
Formatted input is data specified by like has a delimiter or has
specific format associated with it.
This fscanf function takes a file from stream and then a format.
The format is just like the printf format specifiers that you use.
So if you want to read in integers or doubles, you can specify data
inside the file that are introduced in doubles and it will read that
until it sees like just like the scanf until it sees a whitespace character.
So the first argument to the fscanf function is a pointer to a file
object that identifies the stream.
We have to know what file we're reading from.
The second argument to the function is the format.
This is a c string that contains one or more of the following items.
White space character, non-whitespace character, format specifiers.
The usage is the same as the scanf and the in the printf,
but instead it's from a file.
So inside the double quotes, you can put in text, you can put in whitespace
or non-whitespace characters, but the format specifiers are really is
how you're going to read in the data.
And then you specify variables that you want to read it into.
So the function returns the number of input items
successfully matched and assigned.
So here's what it looks like.
You'll notice that the main is creating three character arrays, str1,
str2 and str3, just ten bytes each.
We create an integer called year, we hit a file pointer.
The first thing we do we open up the file.
In this case, we're opening it up for reading and writing.
But we're not going to actually write anything to it, we're just going to
display what we're reading from it.
We check to make sure the file pointer is not equal to null.
And then here, we're actually putting something in the file fputs.
We haven't talked about that yet, but this is writing something.
Focus here on the fscanf.
The fscanf is going to read in formatted data.
And so what it's going to do is it's going to read in three
strings separated by spaces.
And so you see the percent as space percent as space
percent s space percent d.
Then we're saying where we're going to read them into our three
characters array and then our year, and we have to specify the
address operator for our year.
But the data is formatted a specific way when it's written.
And when you read in something that's formatted, you have to understand the
format of the file how it's written.
Here we know that the file is written by separating strings by whitespace.
So that's how we're going to read it in.
And so we can read it in with one call fscanf.
We can use our form as specifiers as our second argument and then
variable number of arguments for each separate of each comma to specify
the data we want to read it into.
And then we just print out that data, the three strings in the year
and then again we close the file.
And so these are the three ways you can read in data from a file.
You can either read in characters, you can read in strings or
you can read formatted data.
And you'll notice the formatted way of doing it is very similar to scanf.
You use format specifiers, variables to read into.
We'll have a challenge on reading data which will get
you more familiar with this.
It's pretty basic.
You're going to do your open calls, you're going to use your
file pointers and you're going to use those three functions.
Thank you.