C working with text files txt. Working with text files. Writing information to a text file

The developed I / O mechanism does not correspond to the generally accepted style of object-oriented programming, in addition, it actively uses operations with pointers, which are considered potentially unsafe in modern protected code execution environments. An alternative for application development is the mechanism of standard I / O classes provided by the C ++ language standard.

Opening files

The most commonly used classes are ifstream for reading, ofstream for writing, and fstream for modifying files.

All streaming I / O classes are indirectly derived from the common ancestor ios, inheriting its functionality entirely. For example, the file open mode is specified by the data member of the open_mode enumerated type, which is defined as follows:

Enum open_mode (app, binary, in, out, trunc, ate);

Below are the possible values \u200b\u200bof the flags and their purpose.

For example, to open a file named test.txt to read data in binary form, write:

Ifstream file; file.open ("test.txt", ios :: in | ios :: binary);

The logical OR operator (|) allows you to create a mode with any combination of flags. So that, when opening a file by recording, you do not accidentally overwrite an existing file with the same name, you must use the following form:

Ofstream file; file.open ("test.txt", ios :: out | ios :: app);

It is assumed that the corresponding header file is connected to the project:

#include

To check whether the file was successfully opened, you can use the construction

If (! File) (// Handle file open error)

Include and Extract Operators

Overridden in file handling classes inclusion operator (<<) записывает данные в файловый поток. Как только вы открыли файл для записи, можно записывать в него текстовую строку целиком:

File<< "Это строка текста";

You can also write the text string piece by piece:

File<< "Это " << "строка " << "текста";

The endl statement ends the input with a carriage return:

File<< "Это строка текста" << endl;

Using the include operator, it's easy to write the values \u200b\u200bof variables or array elements to a file:

Ofstream file ("Temp.txt"); char buff \u003d "The text array contains variables"; int vx \u003d 100; float pi \u003d 3.14159; file<< buff << endl << vx << endl << pi << endl;

As a result of the code execution, three lines of the text file Temp.txt are formed:

The text array contains variables 100 3.14159

Note that numeric values \u200b\u200bare written to the file as text strings, not binary values.

Extract operator (\u003e\u003e) does the opposite. It would seem that to extract symbols from the Temp.txt file recorded earlier, you need to write code like the following:

Ifstream file ("Temp.txt"); char buff; int vx; float pi; file \u003e\u003e buff \u003e\u003e vx \u003e\u003e pi;

However, the extraction operator will stop at the first delimiter (space, tab, or newline character) it finds. Thus, when parsing the sentence "Text array contains variables" only the word "Text" will be written to the buff array, the space is ignored, and the word "array" will become the value of the integer variable vx, and the code execution will "go wild" with an inevitable violation of the data structure. Next, when we discuss the ifstream class, we will show you how to properly organize the file reading from the previous example.

Ifstream class: reading files

As the name implies, the ifstream class is designed to input a file stream. The following are the main methods of the class. Most of them are inherited from the istream class and are overloaded with extended parent functionality. For example, the get function, depending on the call parameter, can read not only a single character, but also a character block.

Now it is clear how to modify the previous example so that using the data retrieval operator gives the expected result:

Ifstream file ("Temp.txt"); char buff; int vx; float pi; file.getline (buff, sizeof (buff)); file \u003e\u003e vx \u003e\u003e pi:

The getline method will read the first line of the file to the end, and the \u003e\u003e operator will assign values \u200b\u200bto the variables.

The following example shows adding data to a text file and then reading the entire file. The while (1) loop is used instead of while (! File2.eof ()) for reasons discussed in.

#include #include using namespace std; int main () (ofstream file; file.open ("test.txt", ios :: out | ios :: app); if (! file) (cout<< "File error - can"t open to write data!"; cin.sync(); cin.get(); return 1; } for (int i=0; i<10; i++) file << i << endl; file.close(); ifstream file2; file2.open("test.txt", ios::in); if (!file2) { cout << "File error - can"t open to read data!"; cin.sync(); cin.get(); return 2; } int a,k=0; while (1) { file2 >\u003e a; if (file2.eof ()) break; cout<< a << " "; k++; } cout << endl << "K=" << k << endl; file2.close(); cin.sync(); cin.get(); return 0; }

The following example shows a loop to read lines from the test.txt file and display them on the console.

#include #include using namespace std; int main () (ifstream file; // create stream object file file.open ("test.txt"); // open file for reading if (! file) return 1; // return on open error char str; // static line buffer // Read and display lines in a loop until eof while (! file.getline (str, sizeof (str)). eof ()) cout<< str << endl; // вывод прочитанной строки на экран cin.sync(); cin.get(); return 0; }

This code under Windows OS also depends on the presence of a line feed character in the last line of the file, it would be safer to do this:

While (1) (if (file.eof ()) break; file.getline (str, sizeof (str)); cout<< str << endl; }

Explicit calls to the open and close methods are optional. Indeed, calling the constructor with an argument allows you to immediately open a file at the time of creating a stream object file:

Ifstream file ("test.txt");

Instead of the close method, you can use the delete operator, which will automatically call the file object's destructor and close the file. The while loop code ensures that the end of file is properly checked.

The ofstream class: writing files

The ofstream class is designed to output data from a file stream. The following are the main methods of this class.

The include operator described earlier is convenient for organizing writing to a text file:

Ofstream file ("temp.txt"); if (! file) return; for (int i \u003d 1; i<=3; i++) file << "Строка " << i << endl; file.close();

Binary files

Basically, binary data is served like text data. The difference is that if binary data is written in a certain logical structure, then it must be read from a file into a variable of the same structure type.

The first parameter of the write and read methods (the address of the write / read block) must be of the char * character pointer type, therefore, an explicit conversion of the address type of the void * structure must be performed. The second parameter specifies that the binary blocks of the file have a constant byte size regardless of the actual record length. The following appendix provides an example of how to create and display data for a basic notebook. The file records are then read sequentially and displayed on the console.

#include #include #include using namespace std; struct Notes (// data structure of the notebook char Name; // full name char Phone; // phone int Age; // age); int main () (setlocale (LC_ALL, "Russian"); Notes Note1 \u003d ("Ivan the Terrible", "not installed", 60); Notes Note2 \u003d ("Boris Fedorovich Godunov", "095-111-2233", 30); Notes Note3 \u003d ("Romanov Petr Mikhailovich", "812-333-2211", 20); ofstream ofile ("Notebook.dat", ios :: binary); ofile.write ((char *) & Note1, sizeof (Notes)); // 1st block ofile.write ((char *) & Note2, sizeof (Notes)); // 2nd block ofile.write ((char *) & Note3, sizeof (Notes)); / / 3rd block ofile.close (); // close the written file ifstream ifile ("Notebook.dat", ios :: binary); Notes Note; // structured variable char str; // static string buffer // Read and display lines in a loop until eof while (! ifile.read ((char *) & Note, sizeof (Notes)). eof ()) (sprintf (str, "% s \\ t Body:% s \\ t Age:% d" , Note.Name, Note.Phone, Note.Age); cout<< str << endl; } ifile.close(); // закрыть прочитанный файл cin.sync(); cin.get(); return 0; }

As a result of executing this code, a binary Notebook.dat file is formed from three blocks of 80 bytes each (provided that the characters are single-byte). Naturally, you can use other streaming methods and perform any operations on the fields of a specific data structure.

Fstream class: random file access

Suppose that there are 100 entries in our notebook, and we want to count the 50th. Of course, you can loop and read all records from the first to the given one. Obviously a more targeted solution is to set the pos file position pointer directly to record 50 and read it:

Ifstream ifile ("Notebook.dat", ios :: binary); int pos \u003d 49 * sizeof (Notes); ifile.seekg (pos); // find the 50th entry Notes Note; // Notes - the above "record" structure ifile.read ((char *) & Note, sizeof (Notes));

Searches like these are effective if the file consists of records of known and constant size. To replace the content of an arbitrary entry, you need to open the output stream in modification mode:

Ofstream ofile ("Notebook.dat", ios :: binary | ios :: ate); int pos \u003d 49 * sizeof (Notes); ofile seekp (pos); // search for the 50th record Notes Note50 \u003d ("Boris Yeltsin", "095-222-3322", 64); ofile.write ((char *) & Note, sizeof (Notes)); // replacement

If you do not specify the ios :: ate (or ios :: app) flag, then when you open the binary Notebook.dat file, its previous contents will be erased!

Finally, it is possible to open a file at the same time for reading / writing, using methods inherited by the fstream stream class from its predecessors. Since the fstream class is derived from istream and ostream (the parents of ifstream and ofstream, respectively), all of the previously mentioned methods are made available in the application.

The following example swaps the first and third entries in the Notebook.dat file.

#include #include #include using namespace std; struct Notes (char Name; char Phone; int Age;); int main () (setlocale (LC_ALL, "Russian"); Notes Note1, Note3; // Open file for reading / writing simultaneously fstream file ("Notebook.dat", ios :: binary | ios :: in | ios :: out); file.seekg (2 * sizeof (Notes)); // find and read Note3 file.read ((char *) & Note3, sizeof (Notes)); file.seekg (0); // find and read Note1 file.read ((char *) & Note1, sizeof (Notes)); file.seekg (0); // Note1<== Note3 file.write((char*)&Note3, sizeof(Notes)); file.seekg(2 * sizeof(Notes)); // Note3 <== Note1 file.write((char*)&Note1, sizeof(Notes)); char str; // Считывать и отображать записи в цикле, пока не eof file.seekg(0); // вернуться к началу файла while (!file.read((char*)&Note1, sizeof(Notes)).eof()) { sprintf(str, "%s\tТел: %s\tВозраст: %d", Note1.Name, Note1.Phone, Note1.Age); cout << str << endl; } file.close(); cin.sync(); cin.get(); return 0; }

The ios :: in and ios :: out flags must be specified in the constructor of the file object, allowing simultaneous read and write operations. As a result of executing this code, the first and third records of the binary Notebook.dat file will be swapped.

There are additional examples on the topic.

Tags: Text files, fopen, fclose, feof, setbuf, setvbuf, fflush, fgetc, fprintf, fscanf, fgets, buffered stream, unbuffered stream.

Working with text files

Working with a text file is similar to working with a console: using formatted input functions, we save data to a file, using formatted output functions, we read data from a file. There are many nuances that we will look at later. The main operations that need to be done are

  • 1. Open the file so that you can refer to it. Accordingly, it is possible to open for reading, writing, reading and writing, rewriting or writing to the end of the file, etc. When you open a file, a bunch of errors may also occur - the file may not exist, it may be the wrong type of file, you may not have permission to work with the file, etc. All this must be taken into account.
  • 2. Directly working with the file - writing and reading. It should also be remembered here that we are not working with random access memory, but with a buffered stream, which adds its own specifics.
  • 3. Close the file. Since the file is a resource external to the program, if it is not closed, then it will continue to hang in memory, possibly even after the program is closed (for example, it will not be possible to delete an open file or make changes, etc.). In addition, sometimes it is necessary not to close, but to "reopen" the file in order, for example, to change the access mode.

In addition, there are a number of tasks when we do not need to access the contents of the file: rename, move, copy, etc. Unfortunately, the C standard does not describe functions for these needs. They are certainly available for each of the compiler implementations. Reading the contents of a directory (folder, directory) is also an access to a file, because a folder itself is a file with meta information.

Sometimes it is necessary to perform some auxiliary operations: move to the desired location in the file, remember the current position, determine the length of the file, etc.

A FILE object is required to work with a file. This object stores the identifier of the file stream and the information needed to manipulate it, including a pointer to its buffer, a file position indicator, and status indicators.

The FILE object is itself a structure, but its fields should not be accessed. A portable program must treat the file as an abstract object that allows access to the file stream.

The creation and allocation of memory for an object of type FILE is carried out using the fopen or tmpfile function (there are others, but we will focus only on these).

The fopen function opens a file. It takes two arguments - a string with the file address and a string with the file access mode. The file name can be either absolute or relative. fopen returns a pointer to a FILE object that can be used to further access the file.

FILE * fopen (const char * filename, const char * mode);

For example, let's open a file and write Hello World to it

#include #include #include void main () (// Using the file variable we will access the file FILE * file; // Open a text file with write permissions file \u003d fopen ("C: /c/test.txt", "w + t") ; // Write to the file fprintf (file, "Hello, World!"); // Close the file fclose (file); getch ();)

The fopen function itself allocates memory for the object, cleaning is carried out by the fclose function. It is mandatory to close the file, it will not close on its own.

The fopen function can open a file in text or binary mode. The default is text. Access mode can be as follows

File access parameters.
A type Description
r Reading. The file must exist.
w Writing a new file. If a file with the same name already exists, then its contents will be lost.
a Writing to the end of the file. Positioning operations (fseek, fsetpos, frewind) are ignored. The file is created if it did not exist.
r + Reading and updating. You can both read and write. The file must exist.
w + Recording and updating. A new file is created. If a file with the same name already exists, then its contents will be lost. You can both write and read.
a + End write and update. Positioning operations are read-only, ignored for writing. If the file did not exist, a new one will be created.

If you need to open a file in binary mode, then the letter b is added to the end of the line, for example, “rb”, “wb”, “ab”, or, for mixed mode, “ab +”, “wb +”, “ab +”. Instead of b, you can add the letter t, then the file will be opened in text mode. It depends on the implementation. In the new C standard (2011), the letter x means that the fopen function should fail if the file already exists. Let's supplement our old program: reopen the file and consider that we have written there.

#include #include #include void main () (FILE * file; char buffer; file \u003d fopen ("C: /c/test.txt", "w"); fprintf (file, "Hello, World!"); fclose (file); file \u003d fopen ("C: /c/test.txt", "r"); fgets (buffer, 127, file); printf ("% s", buffer); fclose (file); getch ();)

You could have used fscanf instead of fgets, but remember that it can only read a line up to the first space.
fscanf (file, "% 127s", buffer);

Also, instead of opening and closing the file, you can use the freopen function, which "reopens" the file with new permissions.

#include #include #include void main () (FILE * file; char buffer; file \u003d fopen ("C: /c/test.txt", "w"); fprintf (file, "Hello, World!"); freopen ("C: / c / test.txt "," r ", file); fgets (buffer, 127, file); printf ("% s ", buffer); fclose (file); getch ();)

The fprintf and fscanf functions differ from printf and scanf only in that they take as their first argument a pointer to a FILE to which they will print or from which they will read data. It is worth adding here right away that the printf and scanf functions can be replaced without any problems with the fprintf and fscanf functions. In the OS (we are considering the most common and adequate operating systems), there are three standard streams: standard output stdout, standard input stdin and standard error stderr. They are automatically opened during application startup and are associated with the console. Example

#include #include #include void main () (int a, b; fprintf (stdout, "Enter two numbers \\ n"); fscanf (stdin, "% d", & a); fscanf (stdin, "% d", & b); if (b \u003d\u003d 0) (fprintf (stderr, "Error: divide by zero");) else (fprintf (stdout, "% .3f", (float) a / (float) b);) getch ();)

File open error

If the fopen function call fails, it will return NULL. Errors while working with files are quite common, so every time we open a file, we need to check the result of the work

#include #include #include #define ERROR_OPEN_FILE -3 void main () (FILE * file; char buffer; file \u003d fopen ("C: /c/test.txt", "w"); if (file \u003d\u003d NULL) (printf ("Error opening file "); getch (); exit (ERROR_OPEN_FILE);) fprintf (file," Hello, World! "); freopen (" C: /c/test.txt "," r ", file); if (file \u003d \u003d NULL) (printf ("Error opening file"); getch (); exit (ERROR_OPEN_FILE);) fgets (buffer, 127, file); printf ("% s", buffer); fclose (file); getch () ;)

The problem is caused by the case when several files are opened at once: if one of them cannot be opened, then the rest must also be closed

FILE * inputFile, * outputFile; unsigned m, n; unsigned i, j; inputFile \u003d fopen (INPUT_FILE, READ_ONLY); if (inputFile \u003d\u003d NULL) (printf ("Error opening file% s", INPUT_FILE); getch (); exit (3);) outputFile \u003d fopen (OUTPUT_FILE, WRITE_ONLY); if (outputFile \u003d\u003d NULL) (printf ("Error opening file% s", OUTPUT_FILE); getch (); if (inputFile! \u003d NULL) (fclose (inputFile);) exit (4);) ...

In simple cases, you can act head-on, as in the previous piece of code. In more complex cases, methods are used that replace RAII from C ++: wrappers, or compiler features (cleanup in GCC), etc.

Buffering data

As mentioned earlier, when we output data, it is first put into a buffer. The buffer is cleared

  • 1) If it is full
  • 2) If the stream is closed
  • 3) If we explicitly indicate that it is necessary to clear the buffer (there are also exceptions here :)).
  • 4) Also cleared if the program ended successfully. At the same time, all files are closed. If the execution fails, this may not happen.

You can force the unloading of the buffer by calling the fflush (File *) function. Let's look at two examples - with and without cleaning.

#include #include #include void main () (FILE * file; char c; file \u003d fopen ("C: /c/test.txt", "w"); do (c \u003d getch (); fprintf (file, "% c", c ); fprintf (stdout, "% c", c); // fflush (file);) while (c! \u003d "q"); fclose (file); getch ();)

Uncomment the fflush call. At runtime, open a text file and observe the behavior.

You can assign a file buffer yourself by setting your own size. This is done using the function

Void setbuf (FILE * stream, char * buffer);

which takes an already open FILE and a pointer to a new buffer. The size of the new buffer must be no less than BUFSIZ (for example, on the current workstation, BUFSIZ is 512 bytes). If you pass NULL as a buffer, then the stream will become unbuffered. You can also use the function

Int setvbuf (FILE * stream, char * buffer, int mode, size_t size);

which takes a buffer of arbitrary size size. Mode can take on the following values

  • _IOFBF - full buffering. Data is written to the file when it is full. On reading, the buffer is considered full when an input operation is requested and the buffer is empty.
  • _IOLBF - linear buffering. Data is written to the file when it is full or when a newline character is encountered. On reading, the buffer is filled up to a newline character when an input operation is requested and the buffer is empty.
  • _IONBF - no buffering. In this case, the size and buffer parameters are ignored.
If successful, the function returns 0.

Example: let's set our own buffer and see how reading from a file is carried out. Let the file be short (something like Hello, World!), And we read it character by character

#include #include #include void main () (FILE * input \u003d NULL; char c; char buffer \u003d (0); input \u003d fopen ("D: /c/text.txt", "rt"); setbuf (input, buffer); while ( ! feof (input)) (c \u003d fgetc (input); printf ("% c \\ n", c); printf ("% s \\ n", buffer); _getch ();) fclose (input);)

You can see that the data is already in the buffer. Reading character by character is performed from the buffer.

feof

Function int feof (FILE * stream); returns true if end of file has been reached. This function is useful when you need to go through the entire file from beginning to end. Let there be a file with text content text.txt. We read the file character by character and display it.

#include #include #include void main () (FILE * input \u003d NULL; char c; input \u003d fopen ("D: /c/text.txt", "rt"); if (input \u003d\u003d NULL) (printf ("Error opening file") ; _getch (); exit (0);) while (! feof (input)) (c \u003d fgetc (input); fprintf (stdout, "% c", c);) fclose (input); _getch ();)

Everything would be fine, only the feof function does not work correctly ... This is due to the fact that the concept of "end of file" is not defined. When using feof, an error often occurs when the last read data is output two times. This is due to the fact that data is written to the input buffer, the last read occurs with an error and the function returns the old read value.

#include #include #include void main () (FILE * input \u003d NULL; char c; input \u003d fopen ("D: /c/text.txt", "rt"); if (input \u003d\u003d NULL) (printf ("Error opening file") ; _getch (); exit (0);) while (! feof (input)) (fscanf (input, "% c", & c); fprintf (stdout, "% c", c);) fclose (input); _getch ();)

This example will fail (most likely) and output the last character of the file twice.

The solution is not to use feof. For example, store the total number of records or take advantage of the fact that fscanf, etc., usually return the number of correctly read and matched values.

#include #include #include void main () (FILE * input \u003d NULL; char c; input \u003d fopen ("D: /c/text.txt", "rt"); if (input \u003d\u003d NULL) (printf ("Error opening file") ; _getch (); exit (0);) while (fscanf (input, "% c", & c) \u003d\u003d 1) (fprintf (stdout, "% c", c);) fclose (input); _getch () ;)

Examples of

1. Two numbers are written in one file - the dimensions of the array. Let's fill the second file with an array of random numbers.

#include #include #include #include // File names and permissions #define INPUT_FILE "D: /c/input.txt" #define OUTPUT_FILE "D: /c/output.txt" #define READ_ONLY "r" #define WRITE_ONLY "w" // Maximum value for array size #define MAX_DIMENSION 100 // Error opening file #define ERROR_OPEN_FILE -3 void main () (FILE * inputFile, * outputFile; unsigned m, n; unsigned i, j; inputFile \u003d fopen (INPUT_FILE, READ_ONLY); if ( inputFile \u003d\u003d NULL) (printf ("Error opening file% s", INPUT_FILE); getch (); exit (ERROR_OPEN_FILE);) outputFile \u003d fopen (OUTPUT_FILE, WRITE_ONLY); if (outputFile \u003d\u003d NULL) (printf ("Error opening file% s ", OUTPUT_FILE); getch (); // If the file was opened for reading, then it must be closed if (inputFile! \u003d NULL) (fclose (inputFile);) exit (ERROR_OPEN_FILE);) fscanf (inputFile, "% ud% ud", & m, & n); if (m\u003e MAX_DIMENSION) (m \u003d MAX_DIMENSION;) if (n\u003e MAX_DIMENSION) (n \u003d MAX_DIMENSION;) srand (time (NULL)); for (i \u003d 0; i< n; i++) { for (j = 0; j < m; j++) { fprintf(outputFile, "%8d ", rand()); } fprintf(outputFile, "\n"); } //Закрываем файлы fclose(inputFile); fclose(outputFile); }

2. The user copies the file, and first selects the operation mode: the file can be output both to the console and copied to a new file.

#include #include #include #define ERROR_FILE_OPEN -3 void main () (FILE * origin \u003d NULL; FILE * output \u003d NULL; char filename; int mode; printf ("Enter filename:"); scanf ("% 1023s", filename); origin \u003d fopen (filename, "r"); if (origin \u003d\u003d NULL) (printf ("Error opening file% s", filename); getch (); exit (ERROR_FILE_OPEN);) printf ("enter mode:"); scanf ( "% d", & mode); if (mode \u003d\u003d 1) (printf ("Enter filename:"); scanf ("% 1023s", filename); output \u003d fopen (filename, "w"); if (output \u003d \u003d NULL) (printf ("Error opening file% s", filename); getch (); fclose (origin); exit (ERROR_FILE_OPEN);)) else (output \u003d stdout;) while (! Feof (origin)) (fprintf (output, "% c", fgetc (origin));) fclose (origin); fclose (output); getch ();)

3. The user enters data from the console and they are written to the file until the esc key is pressed. Check the program and see. how it behaves if you type backspace: what is output to a file and what is output to the console.

#include #include #include #define ERROR_FILE_OPEN -3 void main () (FILE * output \u003d NULL; char c; output \u003d fopen ("D: /c/test_output.txt", "w + t"); if (output \u003d\u003d NULL) (printf ("Error opening file"); _getch (); exit (ERROR_FILE_OPEN);) for (;;) (c \u003d _getch (); if (c \u003d\u003d 27) (break;) fputc (c, output); fputc ( c, stdout);) fclose (output);)

4. The file contains integers. Find the maximum of them. Let's take advantage of the fact that the fscanf function returns the number of correctly read and matched objects. The number 1 should be returned each time.

#include #include #include #define ERROR_FILE_OPEN -3 void main () (FILE * input \u003d NULL; int num, maxn, hasRead; input \u003d fopen ("D: /c/input.txt", "r"); if (input \u003d\u003d NULL) (printf ("Error opening file"); _getch (); exit (ERROR_FILE_OPEN);) maxn \u003d INT_MIN; hasRead \u003d 1; while (hasRead \u003d\u003d 1) (hasRead \u003d fscanf (input, "% d", & num); if (hasRead! \u003d 1) (continue;) if (num\u003e

Another solution is to read numbers until we reach the end of the file.

#include #include #include #include #define ERROR_FILE_OPEN -3 void main () (FILE * input \u003d NULL; int num, maxn, hasRead; input \u003d fopen ("D: /c/input.txt", "r"); if (input \u003d\u003d NULL) (printf ("Error opening file"); _getch (); exit (ERROR_FILE_OPEN);) maxn \u003d INT_MIN; while (! feof (input)) (fscanf (input, "% d", & num); if (num\u003e maxn ) (maxn \u003d num;)) printf ("max number \u003d% d", maxn); fclose (input); _getch ();)

5. The file contains words: Russian word, tabulation, English word, in several rows. The user enters an English word, the Russian must be displayed.

The translation file looks something like this

Sun sun
pencil pen
pencil ballpoint pen
door door
windows window
chair chair
armchair chair

and saved in cp866 (OEM 866) encoding. It is important that the last pair of words also ends with a line feed.

The algorithm is as follows - we read the line from the file, find the tabulation sign in the line, replace the tabulation sign with zero, copy the Russian word from the buffer, copy the English word from the buffer, check for equality.

#include #include #include #include #define ERROR_FILE_OPEN -3 void main () (FILE * input \u003d NULL; char buffer; char enWord; char ruWord; char usrWord; unsigned index; int length; int wasFound; input \u003d fopen ("D: /c/input.txt "," r "); if (input \u003d\u003d NULL) (printf (" Error opening file "); _getch (); exit (ERROR_FILE_OPEN);) printf (" enter word: "); fgets (usrWord, 127, stdin ); wasFound \u003d 0; while (! feof (input)) (fgets (buffer, 511, input); length \u003d strlen (buffer); for (index \u003d 0; index< length; index++) { if (buffer == "\t") { buffer = "\0"; break; } } strcpy(ruWord, buffer); strcpy(enWord, &buffer); if (!strcmp(enWord, usrWord)) { wasFound = 1; break; } } if (wasFound) { printf("%s", ruWord); } else { printf("Word not found"); } fclose(input); _getch(); }

6. Count the number of lines in the file. Let's read the file character by character, counting the number of "\\ n" characters until we come across the EOF character. EOF is a special character that indicates that the input is complete and there is no more data to read. The function returns a negative value on error.
NOTE: EOF is int, so you must use int to read characters. In addition, the EOF value is not defined by the standard.

#define _CRT_SECURE_NO_WARNINGS #include #include #include int cntLines (const char * filename) (int lines \u003d 0; int any; // any of type int, because EOF is of type int! FILE * f \u003d fopen (filename, "r"); if (f \u003d\u003d NULL) (return -1;) do (any \u003d fgetc (f); // printf ("% c", any); // debug if (any \u003d\u003d "\\ n") (lines ++;)) while (any! \u003d EOF); \u200b\u200bfclose (f); return lines;) void main () (printf ("% d \\ n", cntLines ("C: /c/file.txt")); _getch ();)

Ru-Cyrl 18- tutorial Sypachev S.S. 1989-04-14 [email protected] Stepan Sypachev students

Still not clear? - write questions to the mailbox

File I / O work in C ++ is almost the same as normal (but with a few nuances).

File I / O Classes

there is the three main classes of file I / O in C ++:

ofstream (is a child of the class);

fstream (is a child of the iostream class).

You can use these classes to perform unidirectional file input, unidirectional file output, and bidirectional file I / O. To use them, you just need to connect fstream.

Unlike cout, cin, cerr, and clog streams, which can be used immediately, file streams must be explicitly set by the programmer. That is, to open a file for reading and / or writing, you need to create an object of the corresponding file I / O class, specifying the file name as a parameter. Then, using the insert operators (<<) или извлечения (>\u003e), you can write data to a file or read the contents of a file. After that, the final is - you need to close the file: explicitly call close () method or just let the file I / O variable go out of scope (the file I / O class will close this file automatically for us).

File output

The ofstream class is used to write to a file. For instance:

#include #include #include // to use exit () int main () (using namespace std; // ofstream is used to write data to a file // Create a file SomeText.txt ofstream outf ("SomeText.txt"); // If we cannot open this file for writing data to it if (! outf) (// Then display an error message and execute exit () cerr<< "Uh oh, SomeText.txt could not be opened for writing!" << endl; exit(1); } // Записываем в файл следующие две строчки outf << "See line #1!" << endl; outf << "See line #2!" << endl; return 0; // Когда outf выйдет из области видимости, то деструктор класса ofstream автоматически закроет наш файл }

#include

#include

#include // to use exit ()

int main ()

using namespace std;

// ofstream is used to write data to a file

// Create a file SomeText.txt

ofstream outf ("SomeText.txt");

// If we cannot open this file to write data to it

if (! outf)

// Then we display an error message and execute exit ()

cerr<< << endl ;

exit (1);

// Write the following two lines to the file

outf<< "See line #1!" << endl ;

outf<< "See line #2!" << endl ;

return 0;

// When outf goes out of scope, the destructor of the ofstream class will automatically close our file

If you look into your project directory ( Right click on the tab with the name of your .cpp file in Visual Studio > "Open Containing Folder"), you will see a file called SomeText.txt, which contains the following lines:

See line # 1!
See line # 2!

Please note we can also use put () method to write one character to a file.

File input

#include #include #include #include // to use exit () int main () (using namespace std; // ifstream is used to read the contents of the file // Try to read the contents of the file SomeText.txt ifstream inf ("SomeText.txt"); // If we cannot open this file to read its contents if (! inf) (cerr<< "Uh oh, SomeText.txt could not be opened for reading!" << endl; exit(1); } // Пока есть данные, которые мы можем прочитать while (inf) { // То перемещаем эти данные в строку, которую затем выводим на экран string strInput; inf >\u003e strInput; cout<< strInput << endl; } return 0; }

#include

#include

#include

#include // to use exit ()

int main ()

using namespace std;

// ifstream is used to read the contents of the file

// If we cannot open this file to read its contents

if (! inf)

// Then we display the following error message and execute exit ()

cerr<< << endl ;

exit (1);

// As long as there is data that we can read

while (inf)

// Then we move this data to a line, which we then display on the screen

string strInput;

inf \u003e\u003e strInput;

cout<< strInput << endl ;

return 0;

// When inf goes out of scope, the destructor of the ifstream class will automatically close our file

See
line
#1!
See
line
#2!

Hmm, this is not exactly what we wanted. As we already know from the previous lessons, the extract operator works with "formatted data", i.e. it ignores all spaces, tabs and newlines. To read the entire content as it is, without breaking it down into parts (as in the example above), we need to use getline () method:

#include #include #include #include // to use exit () int main () (using namespace std; // ifstream is used to read the contents of the files // We will try to read the contents of the file SomeText.txt ifstream inf ("SomeText.txt"); // If we cannot open the file to read its contents if (! inf) (// Then display the following error message and execute exit () cerr<< "Uh oh, SomeText.txt could not be opened for reading!" << endl; exit(1); } // Пока есть, что читать while (inf) { // То перемещаем то, что можем прочитать, в строку, а затем выводим эту строку на экран string strInput; getline(inf, strInput); cout << strInput << endl; } return 0; // Когда inf выйдет из области видимости, то деструктор класса ifstream автоматически закроет наш файл }

#include

#include

#include

#include // to use exit ()

int main ()

using namespace std;

// ifstream is used to read the contents of files

ifstream inf ("SomeText.txt");

// If we cannot open the file to read its contents

if (! inf)

// Then we display the following error message and execute exit ()

cerr<< "Uh oh, SomeText.txt could not be opened for reading!"<< endl ;

exit (1);

while (inf)

string strInput;

getline (inf, strInput);

cout<< strInput << endl ;

return 0;

// When inf goes out of scope, the destructor of the ifstream class will automatically close our file

The result of running the program above:

Buffered Output

C ++ output can be buffered. This means that everything that is output to the file stream cannot be immediately written to disk (to a specific file). This is done primarily for performance reasons. When buffer data is written to disk, it is called flushing the buffer... One way to clear the buffer is to close the file. In this case, the entire contents of the buffer will be moved to disk, and then the file will be closed.

Output buffering is usually not a problem, but under certain circumstances it can cause problems for unwary novices. For example, when data is stored in a buffer and the program terminates its execution prematurely (either as a result of a crash or by calling). In such cases, file I / O class destructors are not executed, files are never closed, buffers are not flushed, and our data is lost forever. This is why it is a good idea to explicitly close all open files before calling exit ().

Also the buffer can be cleared manually using ostream :: flush () method or by sending std :: flush to the output stream. Any of these methods can be useful to ensure that the contents of the buffer are written to disk immediately in the event of a program failure.

An interesting nuance: Since std :: endl; also clears the output stream, its excessive use (leading to unnecessary buffer flushes) can affect the performance of the program (since flushing the buffer in some cases can be a costly operation). For this reason, programmers who care about the performance of their code often use \\ n instead of std :: endl to insert a newline into the output stream to avoid unnecessary flushing of the buffer.

File open modes

What happens if we try to write data to an existing file? Restarting the program above (the very first) shows that the original file is completely overwritten when the program is restarted. What if we need to append data to the end of the file? It turns out that the file stream takes an optional second parameter, which allows you to tell the programmer how to open the file. As this parameter, you can pass following flags (which are in the ios class):

app - opens the file in add mode;

ate - goes to the end of the file before reading / writing;

binary - opens the file in binary mode (instead of text mode);

in - opens the file in read mode (default for ifstream);

out - opens the file in recording mode (default for ofstream);

trunc - deletes the file if it already exists.

You can specify several flags at once by using.

ifstream works in ios :: in mode by default;

ofstream works in ios :: out mode by default;

fstream by default runs in ios :: in OR ios :: out mode, which means you can do both reading the contents of the file and writing data to the file.

Now, let's write a program that adds two lines to the previously created SomeText.txt file:

#include #include // to use exit () #include int main () (using namespace std; // Pass the ios: app flag to tell fstream that we're going to add our data to the existing file data, // we're not going to overwrite the file. We don't need to pass the ios :: out flag , // since ofstream by default works in ios :: out ofstream outf mode ("SomeText.txt", ios :: app); // If we cannot open the file to write data if (! outf) (// Then we output following error message and execute exit () cerr<< "Uh oh, SomeText.txt could not be opened for writing!" << endl; exit(1); } outf << "See line #3!" << endl; outf << "See line #4!" << endl; return 0; // Когда outf выйдет из области видимости, то деструктор класса ofstream автоматически закроет наш файл }

#include

#include // to use exit ()

#include

int main ()

using namespace std;

// Pass the ios: app flag to tell fstream that we're going to add our data to the existing file data,

// we're not going to overwrite the file. We don't need to pass the ios :: out flag,

// since ofstream by default works in ios :: out mode

ofstream outf ("SomeText.txt", ios :: app);

// If we cannot open the file to write data

if (! outf)

// Then we display the following error message and execute exit ()

cerr<< "Uh oh, SomeText.txt could not be opened for writing!"<< endl ;

exit (1);

Files allow the user to read large amounts of data directly from disk without entering it from the keyboard. There are two main types of files: text and binary.

Text files consisting of any characters are called. They are organized into lines, each of which ends with " end of line "... The end of the file itself is indicated by the symbol " end of file "... When writing information to a text file, which can be viewed using any text editor, all data is converted to a character type and stored in character form.

AT binary files, information is read and written in the form of blocks of a certain size, which can store data of any kind and structure.

To work with files, special data types are used, called streams.Flow ifstreamserves to work with files in reading mode, and ofstream in recording mode. To work with files in both write and read mode, use the stream fstream.

In C ++ programs, when working with text files, you need to include libraries iostream and fstream.

In order to write data to a text file, you must:

  1. describe a variable of type ofstream.
  2. open.
  3. output information to a file.
  4. be sure to close the file.

To read data from a text file, you must:

  1. describe a variable of type ifstream.
  2. open file using function open.
  3. read information from the file; when reading each piece of data, it is necessary to check whether the end of the file has been reached.
  4. close the file.

Writing information to a text file

As mentioned earlier, in order to start working with a text file, you need to describe a variable of the type ofstream... For example, like this:

ofstream F;

A variable will be created F to write information to a file. The next step is to open the file for writing. In general, the stream opening operator will look like this:

F.open("File", mode);

Here F is a variable described as ofstream, file - full name of the file on disk, mode - mode of operation with the file being opened. Please note that you must use a double slash when specifying the full file name. To access, for example, a file accounts.txt, located in the folder sites on disk D, the program must specify: D: \\\\ sites \\\\ accounts.txt.

The file can be opened in one of the following modes:

  • ios :: in - open the file in data reading mode; mode is the default mode for streams ifstream;
  • ios :: out - open the file in the data recording mode (the information about the existing file is destroyed); mode is the default mode for streams ofstream;
  • ios :: app - open the file in the mode of writing data to the end of the file;
  • ios :: ate - move to the end of an already open file;
  • ios :: trunc - clear the file, the same happens in the ios :: out mode;
  • ios :: nocreate - do not open a file if it does not exist;
  • ios :: noreplace - do not open an existing file.

The mode parameter can be absent, in this case the file is opened in the default mode for this stream.

After successfully opening the file (in any mode) in the variable F will be kept true, otherwise false... This will check the correctness of the file open operation.

Open a file (take the file D: \\\\ sites \\\\ accounts.txt) in recording mode in one of the following ways:

After opening the file in write mode, an empty file will be created in which you can write information.

If you want to open an existing file in the rewrite mode, use the value ios :: app.

After opening a file in write mode, you can write to it in the same way as to the screen, only instead of the standard output device cout you must specify the name of the open file.

For example, to write to the stream Fvariable a, the output operator will be:

F<

For sequential output to a stream G variables b, c, d the output statement becomes:

G<

The stream is closed using the operator:

F.close ();

Consider the following problem as an example.

Problem 1

Create text file D: \\\\ sites\\accounts .txt and write to it n real numbers.

Decision

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

#include "stdafx.h"
#include
#include
#include
using namespace std;
int main ()
{

int i, n;
double a;
// describes a stream for writing data to a file
ofstream f;
// open the file in write mode,
// ios :: out mode is set by default
f.open ("D: \\\\ sites \\\\ accounts.txt ", ios :: out);
// enter the number of real numbers
cout<< «n=» ; cin >\u003e n;
// loop for entering real numbers
// and write them to a file
for (i \u003d 0; i< n; i++ )
{
cout<< «a=» ;
// enter a number
cin \u003e\u003e a;
f<< a<< «\\ t ";
}
// close the stream
f.close ();
system ("pause");
return 0;
}

Reading information from a text file

In order to read information from a text file, you must declare a variable of the type ifstream... After that, you need to open the file for reading using the operator open... If the variable is called F, then the first two operators will be like this:

After opening a file in read mode, you can read information from it in the same way as from the keyboard, only instead of cin you need to specify the name of the stream from which the data will be read.

For example, to read data from a stream F into a variable a, the input statement will look like this:

F \u003e\u003e a;

Two numbers in a text editor are considered separated if there is at least one of the characters between them: space, tabulation, end-of-line character. It is good when the programmer knows in advance how many and what values \u200b\u200bare stored in a text file. However, often only the type of values \u200b\u200bstored in the file is known, and their number may vary. To solve this problem, it is necessary to read the values \u200b\u200bfrom the file one by one, and before each reading, check whether the end of the file has been reached. And the function will help to do this F.eof ()... Here F- thread name, the function returns a boolean value: true or false, depending on whether the end of the file has been reached.

Therefore, the loop for reading the contents of the entire file can be written like this:

For a better assimilation of the material, consider the problem.

Problem 2

The text file D: \\\\ game \\\\ accounts.txt stores real numbers, display them on the screen and calculate their number.

Decision

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

#include "stdafx.h"
#include
#include
#include
#include
using namespace std;
int main ()
{
setlocale (LC_ALL, "RUS");
int n \u003d 0;
float a;
fstream F;
// open the file in read mode
F.open ("D: \\\\ sites \\\\ accounts.txt ") ;
// if the file was opened correctly, then
if (F)
{
// loop for reading values \u200b\u200bfrom a file; the execution of the cycle will be interrupted,
// when we reach the end of the file, in this case F.eof () will return true.
while (! F.eof ())
{
// read the next value from stream F into variable a
F \u003e\u003e a;
// display the value of the variable a to the screen
cout<< a<< «\\ t ";
// increase the number of read numbers
n ++;
}
// close the stream
F.close ();
// input to the screen the number of read numbers
cout<< «n=» << n<< endl;
}
// if the file was opened incorrectly, then the output
// messages about the absence of such a file
else cout<< " The file does not exist"<< endl;
system ("pause");
return 0;
}

This concludes the relatively voluminous lesson on text files. The next article will look at the manipulation techniques that C ++ handles.