File input / output in C
Original: Ilia Yordanov, Loobian@cpp-home.com
Introduction
This tutorial will begin with C most basic file I / O (output / output). Since then, I will show you some techniques from a more in-depth aspect and analyze some useful functions.
You need to have a better understanding of C , otherwise this tutorial will be unfamiliar and useless.
Your first program
First of all, I will give a code, then explain one by line. Our first program will create a file and write some characters:
#include
Void main () // The program starts from here {
OFSTREAM Savefile ("CPP-Home.txt");
Savefile << "Hello World, from www.cpp-home.com and lotion!";
Savefile.close ();
Just this? That's right! This program will create a file called cpp-home.txt in the current run directory and write it to it "Hello World, from www.cpp-home.com and loke!".
The meaning of each line is given below:
#include
Declaring a number of classes in this header, including IFStream, OFSTREAM, and FSTREAM, they all inherit from ISTREAM and OSTREAM classes.
OFSTREAM Savefile ("CPP-Home.txt");
1) OFSTREAM is "Output File Stream". It will create a handle so that we will write files in the form of a file stream.
2) Savefile - This is the name of the file handle, of course, you can also switch any of the names you want.
3) ("cpp-home.txt"); - Open the file called cpp-home.txt. If the current directory runs in the program already exists, it will be replaced; if there is no existence, the program will create a file for you, you don't have to worry about it.
Now let us go deep into a little bit. First of all, I have to point out that ostream is a class. So OFStream Savefile; this statement will create an object of such a class; and we will pass the parameters transmitted in parentheses actually pass to constructor: here we will build the files we have to build The name is passed as the actual parameter to the constructor of this class. Of course, we can also pass some other information, but I will explain it later.
Savefile << "Hello World, from www.cpp-home.com and lotion!"; - "<<" It is very kind? Yes, I want you to see it in cout <<. This is a predefined optic operator. Regardless of how to say, this line statement is done, writing the text above into the file. As mentioned earlier, Savefile is a file handle that is associated with an open stream file. Therefore, we only have to enter the handle, followed by "<<", and then write the text enclosed in a series of quotes, you can implement the writing of the file. If we want to write a variable of a variable rather than a quotation number, it is only likely to pass the variable to the handle object like usually using cout <<, like this: savefile << variablename;
Yes!
Savefile.close (); - Since we opened a stream file, then when we finished it, it must be closed. Savefile is an object of the OFStream class, and this class has a member function for turning off file, a Close () function. Therefore, we can turn off the file as long as we enter the file handle name, point number and close ().
Note: Once you turn off the file, you can't access it before you reopen it.
The above is the simplest program that can write files. It's really easy! However, as you are about to be seen in the later part of the tutorial, there are more things to learn!
Read file
You have seen how you should write a file. Now, when we have got a cpp-home.txt file, we will read it and print the content on the screen.
First of all, I have to point out that there are many ways to read files. I will introduce you to all methods (I know). At this moment, I will show you the best way (I think).
As you are already familiar - I will first give a program code, then I will explain it in detail:
#include
Void main () // Program starts here
{
IFStream OpenFile ("cpp-home.txt");
CHAR CH;
While (! OpenFile.eof ())
{
OpenFile.get (CH);
Cout << CH;
}
Openfile.close ();
}
You have to understand the meaning of the first line, and the remaining part will be explained by me.
IFStream OpenFile ("cpp-home.txt") - I guess it will be familiar with now, you will be familiar! IFStream represents "Input File Stream". In the previous program, it is OFStream, its meaning is "Output File Stream". The program in the previous section is a write operation of the file, which is why it is expressed in "Output". The program of this section is to read a file, which is why it is expressed in "INPUT". The remaining code left in this line should be familiar: OpenFile is an object of the IFStream class, which will associate an input file stream; and use the quotation number, it is the name of the file to open.
Please note: There is no test for the file to be opened here! I will point out how to test it later.
CHAR CH; - Declare an array of type char. Just a little to remind you: ARRAYS can only store an ASCII character. While (! openfile.eof ()) - If the end of the file has been reached, the EOF () function returns a non-zero value. So this loop we designed will continue until our file operation arrives at the end of the file. This way we can traverse the entire file in order to read it.
OpenFile.get (CH); - OpenFile is an object of class ifstream. This class declares a member function called GET (). As long as we own the object, we naturally call this function. The get () function reads a character from the corresponding stream file and returns it to the variable. In this example, the GET () function is only one parameter - a variable used to store the read character. Therefore, the program will read a character from the OpenFile stream and store the variable CH from the OpenFile stream.
Note: If you call this function again, it will read the next character, not the original one! Will you understand why you will be like this.
This is why we have to repeatedly loop until the read operation arrives at the end of the file. Every time you cycle, we will read a character and save it in the CH.
COUT << ch; - Displays the CH variable, which saves the read character.
File.close (); - We open a streaming file, you need to close it. Use the close () function to turn it off, which is the same as the previous section!
Note: Once you turn off a file, you can't access it before you reopen it.
Come it! I hope you can understand my explanation. When you compile and run this program, it should output:
"Hello World, from www.cpp-home.com and lotion!"
Master input / output flow
In this chapter, I will mention some useful functions. I will demonstrate how to open a file that can be read and written at the same time; in addition, I will introduce you to other ways to open the file, and how to determine whether the open operation is successful. Therefore, please read down!
So far, I have been only a single open file for you: either open for reading, or open for writing. But files can also be opened in other ways. To date, you should have already met the following methods:
IFStream OpenFile ("cpp-home.txt");
Oh, this is not the only way! As mentioned earlier, the above code creates a class IFStream object and passes the name of the file to its constructor. However, in fact, there are many heavy-duty constructors that accept more than one parameters. At the same time, there is an Open () function to do the same thing. Below is an example of one or more code, but it uses the Open () function:
IFStream OpenFile;
OpenFile.open ("cpp-home.txt");
You will ask: What is the difference between them? Oh, I have done a lot of tests, the conclusion is different! Just if you want to create a file handle but don't want to specify a file name immediately, you can use the open () function to be specified. By the way, an example of using an Open () function is given: If you open a file, then turn it off, it is intended to open another file with the same file handle, so that you will need to use the open () function.
Consider the following code example:
#include
{
// the method to read a file, That i showed you before
CHAR CH;
While (! t.eof ())
{
T.Get (CH);
Cout << CH;
}
COUT << Endl << "--------" << endl;
}
void main ()
{
IFStream T ("file1.txt");
Read (t);
T.close ();
T.Open ("File2.txt");
Read (t);
T.close ();
}
According to this, as long as file1.txt and file2.txt are stored and stored, you will see it.
Now, the file name is not the only parameter you only pass to the Open () function or constructor (actually the same). Below is a function prototype:
IFStream OpenFile (CHAR * filename, int open_mode);
You should know that FileName represents the name of the file (a string), and the new appearance is Open_Mode. Open_MODE value is used to open the file in what way. Here is a list of open modes:
name
description
ios :: in
Open a readable file
iOS :: OUT
Open a writable file
ios :: app
All the data you write will be appended to the end of the file, this way you use ios :: OUT
ios :: ATE
All the data you write will be appended to the end of the file, this way does not use ios :: OUT
ios :: Trunk
Delete the file originally existing content (empty file)
ios :: nocreate
If the file to be opened does not exist, call the open () function in this parameter will not be possible.
ios :: Noreplace
If the file to be opened already exists, you try to open an error when you open with the open () function.
ios :: binary
Open a file in binary form.
In fact, the above values belong to an enumerated type INT constant. But in order to make your programming career is too painful, you can use those names like you see it.
Here is an example of how to use open mode:
#include
void main ()
{
OFSTREAM Savefile ("File1.txt", iOS :: ATE);
Savefile << "That's new! / N";
Savefile.close ();
}
As you can see in the table: Use ios :: ATE will start writing from the end of the file. If I don't use it, the original file content will be overwritten. However, since I have already used it, then I will only add it at the end of the original file. So, if File1.txt is like this:
Hi! This is test from www.cpp-home.com!
So after executing the above code, the program will add "That's New!", So it will turn this:
Hi! This is test from www.cpp-home.com! That's New!
If you plan to set up more than one open mode flag, you only need to use the OR operator or |, like this:
ios :: Ate | os :: binary I hope now you have understood what "Open Mode" means!
Now, it is time to show you some truly useful things! I have to bet you still don't know how to open a file that can be read and written simultaneously! The following is a method of implementing:
FStream File ("cpp-home.txt", ios :: in | os :: out);
In fact, this is just a statement statement. I will give you a code example after the following rows. But at this time, I first want to mention some content you should know.
The above code creates a handle of a stream file called "file". As you know, it is an object of the FStream class. When using FSTREAM, you should specify ios :: in and iOS :: OUT as the open mode of the file. This way, you can read the files at the same time, and you don't have to create a new file handle. Oh, of course, you can only read or write operations. That way, you should use only iOS :: in or only iOS :: OUT - To think about: If you plan to do this, why don't you use IFStream and OFSTREAM to be implemented?
Let's give the sample code first:
#include
Void main () {
FStream File ("Test.txt", ios :: in | os :: out);
File << "hi!"; // Write "Hi!" Into the file
Static Char Str [10]; // When using STATIC, the array will automatically initialize
// is emptied to zero file.seekg (ios :: beg); // Back to the header
// This function will explain later
File >> STR;
COUT << str << endl;
File.Close ();
OK, there are some new things here, so I will explain their progressive:
FStream File ("Test.txt", iOS :: in | iOS :: out); - This line creates a FSTREAM object, which will open the Test.txt file in read / write. This means you can read the files at the same time and write data.
File << "hi!"; - I bet you already know what it means.
Static char str [10]; - This will create a character array of capacity 10. I guess static or some strangers for you, if this is ignored it. This is only initialized while creating an array.
File.seekg (ios :: beg); - OK, I want you to understand what it will do, so I will start with some a bit of the problem, but quite important content starts my explanation.
Remember it:
While (! OpenFile.eof ())
{
OpenFile.get (CH);
Cout << CH;
}
Are you very much looking to know what operations do you really do behind? Whether it is or not, I will explain it for you. This is a WHILE type loop, which will continue until the program's operation reaches the end of the file. But how does this loop know if it has arrived at the end of the file? Well, when you read the file, there will be something similar to "Inside-Pointer", which indicates that you read (written) which position has arrived, just like notepad cursor. And whenever you call OpenFile.Get (CH), it returns the character of the current location, stored in a CH variable and moves this built-in pointer forward. So the next function is called again, it will return next character. This process will continue to repeat until the end of the file is read. So let's go back to the code: function seekg () will position the built-in pointer to the specified location (determined by you). You can use: ios :: beg - Move it to the head of the file
iOS :: End - Move it to the end of the file
Alternatively, you can set the number of characters that jump forward or backward. For example, if you want to position 5 characters positioned to the current location, you should write:
File.seekg (-5);
If you want to skip 40 characters, you should write:
File.seekg (40);
At the same time, I must point out that the function seekg () is overloaded, and it can also bring two parameters. Another version is like this:
File.seekg (-5, iOS :: end);
In this example, you will be able to read the last 4 characters of the file text because:
1) You reach the end (ios :: end)
2) You then reached the position of the top five characters at the end (-5)
Why do you read 4 characters instead of 5? Hey, I only have to think that the last one is "throwing", because the end of the file is neither a character is not a blank character, that is just a location (the translation: maybe iOS :: End "finger" Being out of the scope of the file itself, it is specifically that it is a next position to the last character of the file. It is a bit similar to the END iteration point of each container in STL to point to the next position of the last element. This design may be easy to circulate Traversing in traversal).
You may want to know why I want to use this function. Hey, when I wrote "Hi" into the document, the built-in pointer will be set to it later ... which is the end of the file. So I must set the built-in pointer to the file start. This is the exact use of this function here.
File >> Str; - This is also fresh! Oh, I am sure that this line of code lets you think of CIN >>. In fact, there is a considerable relationship between them. This line will read a word from the file and store it in the specified array variable.
For example, if there is such text pieces in the file:
Hi! Do you know me?
With File >> STR, you will only output "Hi!" To the STR array. You should have already noticed that it is actually read the space as a separator of the word.
Since I have only a single "hi!" In the file, I don't need to write a while loop, which will take more time to write the code. This is why I use this method. By the way, until now, in the While loop of the read file I use, the way the program read file is read by a character. However, you can also read a word in a word, like this:
Char Str [30]; // The length of each word cannot exceed 30 characters while (! OpenFile.eof ())
{
Openfile >> Str;
Cout << Str;
}
You can also read it in a line, like this:
Char line [100]; // Each whole line will be stored here while (! openfile.eof ()) {
OpenFile.getLine (Line, 100); // 100 is the size of the array
Cout << line << endl;}
You may now want to know which method should be used. Well, I suggest you use the way you read by line or read the way I mentioned. The way to read by words is not a good solution, because it does not read the new line of information, so if you have a new line in your file, it will not display the contents of the content, Instead, add the text that has been printed. And use getLine () or get () will show you the original face!
Now, I will tell you how to detect whether the file is open. Really, a good method is small, I will involve them. It should be noted that when "X" appears, it can actually replace "O", "i", or you can nothing (that will be a FSTREAM object).
Example 1: The most common practice
Xfstream File ("cpp-home.txt");
IF (! file) {
Cout << "Error Opening The File! Aborting ... / n";
Exit (1);
Example 2: If the file has been created, return an error
OFSTREAM File ("Unexisting.txt", iOS :: nocreate;
IF (! file)
{
Cout << "Error Opening The File! Aborting ... / n";
Exit (1);
}
Example 3: Using a FAIL () function
OFSTREAM File ("Filer.txt", ios :: nocreate;
IF (file.fail ())
{
Cout << "Error Opening The File! Aborting ... / n";
Exit (1);
}
The new thing in Example 3 is a FAIL () function. If there is any input / output error (not at the end of the file), it will return a non-zero value.
I also have to talk about some content I think it is very important! For example, if you have created a stream file object, you didn't open the file operation, like this:
Ifstream file; // can also be an OFStream
This way, we have a file handle, but we still have not opened the file. If you plan to open it later, you can use the open () function to implement it, I have already introduced it in this tutorial. But if you are in your program, you may need to know if the current handle is associated with an open file, then you can use is_open () to detect. If the file is not open, it will return 0 (false); if the file has been opened, it will return 1 (true). E.g:
OFSTREAM FILE1;
File1.Open ("file1.txt");
Cout << file1.is_open () << endl;
The above code will return 1 (the translation: refers to the file1.is_open () function, the following sentence is the same), because we have opened a file (in the second line). The following code will return 0, which is because we didn't open the file, but only created a stream file handle: OFSTream file1;
Cout << file1.is_open () << endl;
Ok, this chapter is enough.
Detect input / output status flag
Here I don't plan to explain the meaning of the word "flag", but if you really don't understand the concept about this, then you will read it later, you will get some understanding, I also believe You can also understand the theory of this part. Despite this, if you still don't understand the meaning of the flag in C , I recommend you to read some information about this topic.
Ok, let's get started.
The input / output system responsible in C includes record information about the results of each input / output operation. These current status information is included in the object of the IO_STATE type. IO_STATE is an enumeration type (like Open_Mode), the following is the value it contains (the translation: the first list as the enumeration value in the table, the second list is the corresponding meanings of this value):
godbit
No error
Eofbit
Document
Failbit
Non-fatal input / output error
Badbit
Input / output error
There are two ways to get the status information of the input / output. One way is to return the RDState () function, which will return the error tag of the current state (mentioned in the table below). For example, if there is no error, RDState () will return to Goodbit.
Another method is to use any of the following functions to detect the corresponding input / output status:
Bool bad ();
BOOL EOF (); / / Remember it? "Constantly read the file content until the end of the file!"
Bool fail (); //, this is also an old friend ... Testing if an open operation is successful
Bool good ();
If the Badbit flag is marked (the original text is "if The Badbit Flag IS Up", "IS UP" is translated into "marking", which means that the BADBIT corresponds to the error, the BADBIT status is set as the current error. State, the following, the BAD () function returns true; if the Failbit flag is marked, the fail () function returns true; if there is no error (the goodbit flag is marked), the good () function returns true; if The operation has arrived at the end of the file (EOFBIT is marked), then the EOF () function returns True.
If the error occurs, you have to clear these error status so that your program can continue to run correctly - if you are going on. To clear the wrong status, you need to use the CLEAR () function. This function takes a parameter, which is a logo value you will be set to the current state. If you want your program to "clear and cool", as long as IOS :: goodbit is used as the argument. You will see the sample code in the following.
I will show you sample code to consolidate the theoretical knowledge you have learned.
Example 1: Simple state detection
// In practical applications, filestream can be replaced with the file flow handle you used accordingly.
IF (filestream.rdstate () == ios :: EOFbit)
COUT << "End of File! / N"; if (filestream.rdstate () == ios :: badbit)
COUT << "Fatal I / O Error! / N";
IF (filestream.rdstate () == iOS :: Failbit)
COUT << "Non-Fatal I / O Error! / N";
IF (filestream.rdstate () == ios :: goodbit)
COUT << "no errors! / n";
Example 2: Clear () function
#include
void main ()
{
OFSTREAM FILE1 ("file2.txt"); // Establish File2.txt
File1.close ();
// The following detection code will return an error, because I use ios :: NorePlace Open mode
// It mode returns an error when trying to open an existing file
OFSTREAM TEST ("File2.txt", ios :: Noreplace;
// The last line will cause ios :: Failbit error, we will show it out
IF (Test.rDState () == iOS :: Failbit)
Cout << "error ...! / n";
Test.clear (iOS :: Goodbit); // Reset the current state to iOS :: Goodbit
IF (Test.rdState () == iOS :: Goodbit) // Whether the detector has been properly implemented
COUT << "Fine! / N";
Test.clear (ios :: eofbit); // Set the status sign to iOS :: EOFbit. No practical use.
IF (Test.rDState () == iOS :: EOFBIT) // Detects whether to set up COUT << "EOF! / N";
Test.close ();
}
In addition to using the tag value, you can also use a function (translation: refer to BAD (), EOF (), Fail (), and good () these functions, both actually the same - all detection Whether a tag is marked. I have already introduced these functions, I will no longer be repeated. If you are not very sure how to use them, then you will re-review the part of this tutorial that I have demonstrated how to detect a file to open the operation. There I used a fail () function there.
Treatment of binary files
Although there is a format (formatted) text (all files I discussed so far) is very useful, but sometimes you need to use unformatted files - binaries. They look like your executables, and files created with the << and >> operator are greatly different. GET () function and put () function gives you the ability to read / write a rule of format file: To read a byte, you can use the get () function; use the PUT () function to write a byte. . You should recall GET () - I used it. You may puzzle why we use it when we use it, the file content that outputs to the screen looks a text format? Well, I guess this because I used << and >> operators before.
Translation: The author's so-called "formatted text" is the non-text of our usual text format, and relative "unformatted files" to store all kinds of data or executable code. Format file. Typically, the latter needs to read in memory, parsing in the binary level, and the former can be read / written directly from a predetermined << and >> operator (of course, the latter can also be properly reloaded <
If you want to read / write a whole piece of data, you can use the read () and write () functions. The prototypes are as follows:
iStream & Read (Char * BUF, Streamsize Num);
Ostream & Write (Const Char * BUF, Streamsize Num);
For the read () function, the BUF should be an array of characters, and the data read by the file will be saved here. For Write () functions, BUF is a character array that is used to store data you want to write to files. For these two functions, NUM is a number, which specifies the number of bytes you want to read / written from the file.
If you read the data, you have reached the end of the file before you read "NUM" bytes, then you can learn about the number of bytes actually read by calling the gcount () function. This function returns the number of bytes actually read on the read operation of the last time the last time.
Before giveing the sample code, I have to add that if you want to read / write the file in a binary method, you should add ios :: binary as the open mode to the file open parameter table.
Let me showcase sample code now, you will see how it works.
Example 1: Using GET () and PUT ()
#include
void main ()
{
FSTREAM File ("Test_File.txt", ios :: Out | iOS :: in | ios :: binary;
CHAR CH;
CH = 'o';
File.put (ch); // write the contents of the CH into the file
File.seekg (iOS :: beg); // Position to the head of the file
File.get (CH); // Read a character
Cout << ch << endl; // display it on the screen
File.Close ();
}
Example 2: Using Read () and Write ()
#include
#include
void main ()
{
FSTREAM File ("Test_File.txt", ios :: Out | iOS :: in | ios :: binary;
Char arr [13];
STRCPY (Arr, "Hello World!"); // Put Hello World!
File.write (Arr, 5); // Write the top 5 characters - "Hello"
File.seekg (iOS :: beg); // Position to the head of the file
Static Char Read_Array [10]; // I will intend to read some data here.
File.read (Read_Array, 3); // Read the top three characters - "Hel" cout << oorray << Endl; // Output
File.Close ();
}
TELLG () - Returns an INT type value that represents the current location of the "Built-in pointer". This function is only valid when you read a file. For example: #include
The following is an example: #include
Consider the following code: #include