What is fstream in C.

Programs store their information in variables. Unfortunately, these are only retained until the next power failure or operating system crash. And when the program is exited, its content is history as well. So that you can still have powerful access to your data tomorrow, it is advisable to save it in a file. To do this, you can write the data to the file as an output stream. The procedure corresponds to the screen output via cout. This form is called sequential because the data ends up in the file one after the other in the order in which it was written. You can also write a data block anywhere in the file. You can later retrieve this data block by positioning the internal file pointer at this point and reading the data block again. This procedure is typical for classes, especially if they are to be stored in some sort of sorted manner.

fstream

Objects of the class are used for file operations fstream used. If the file is only written to, the class ofstream be used. The class is ideal for pure input files ifstream at. Input and output operators (and) can be applied to the objects of these classes. Before access, the file must be opened with the member function. You can also do the job of opening the fstream-Class by passing the file name as a parameter to the object when it is defined. After editing the file, it must be closed again using the member function. The destructor also takes on this task automatically, so you only have to call it if you want to close a file before the object is resolved.

[Text output to a file]

#include using namespace std; int main () {fstream f; f.open ("test.dat", ios :: out); f << "This text goes into the file" << endl; f.close (); }

Open and close

Constructor

In the listing, an object of the class fstream Are defined. The file is then opened by calling the function. The next line redirects a string to the file, and finally the call to closes the file.

Parameters of open ()

The parameters of the function are first of all the name of the file to be opened. The second parameter is the mode in which the file is opened. In the example, the file is used for output. The parameters of can also be given when defining the object. This calls a constructor that opens the file immediately. fstream f ("test.dat", ios :: out);

Filename

The file name is a C string, i.e. as a pointer to char declared. In most cases you will simply adopt file names from file selection dialogs or user input. If the file name is defined as a constant in the program, remember that the backslash path separator must be written twice, otherwise it will be interpreted as a special character in a string. Otherwise, we recommend using a slash as a path separator. It is also accepted as a path separator under MS Windows. This is not only easier to read, but has its advantages in the portability to UNIX systems. There, the slash and not the backslash is used as a path separator.

File mode

The second parameter specifies the mode in which the file is opened. The constant in the sample program says that the file will be opened for writing. Obviously, use when you want to use a file for reading. The mode means that the file will be emptied when it is opened. This only makes sense if the file is to be written.

ios :: app

The situation is similar with the mode. This appends all outputs to the file. This mode is also sensibly used in combination with. This write mode is particularly important when writing log files. This ensures that the data is always appended to the end of the file. Instead of first determining the size of the file and, from this, the write position, a simple write call is sufficient. The mode has the effect that the position indicator is initially set to the end of the file when the file is opened. In order to combine several modes, they are linked bit by bit with OR. So you put a simple, vertical line between the mode constants. [File modes]
constant importance
ios :: in To read
ios :: out To write
ios :: trunc File is emptied when opened
ios :: app Append written data to the end
ios :: ate Put position indicator at the end

ofstream and ifstream

There are two special stream classes. The class implies as a mode when opening the file. So the class specializes in reading files. The counterpart is that is responsible for files that are only written. This does not need to be mentioned explicitly when opening the file.

binary

By default, C ++ assumes that a file is a text file. As a result, linefeeds are treated differently depending on the platform. In a UNIX environment, a line feed is encoded with the ASCII character 10 (Line Feed). A Macintosh (Classic) uses 13 for carriage return, and Microsoft's operating systems use a combination of both. When reading and writing files, adjustments may be made, but these are fatal if the data is not text but binary data. To prevent this from happening, the option is used when opening data-only files.

Shut down

A file is automatically closed by the destructor. In this respect, calling the function is actually superfluous. Explicitly closing it would even have the disadvantage that there is a stream object that no longer has access to a file. In this respect, opening with the constructor and closing with the destructor is a bit more elegant. On the other hand, a smart programmer will want to close a file opened for writing as quickly as possible. A file opened for writing is vulnerable as long as it is not closed again. If the program crashes before closing the file, its content may be defective.

Read and write

The purpose of a file is to hold data. Text files are different from data files. Text files can be edited using the input and output operators. You can read and edit such files with any editor. Data files, on the other hand, are typically written to and read with data blocks of fixed length.

Data stream

The stream objects for files can be treated for input and output in the same way as they can be handled by cin and cout know from here. The following example shows the output to a file again using the output operator: fstream file (..., ios :: out); ... file << "This goes to a file" << Variable << endl;

Of course, manipulators can also be used for the file output to format the output. Reading from files can be done in an analogous way using the input operator.

Read out file

The input operator works with fstreamObjects in the same way as with cin. The file is read as if its contents came from the keyboard. This includes that spaces, tabs and line feeds are interpreted as input separators. This also applies when the data stream flows in character string variables.

Read line of text

In order to be able to read lines of text with spaces from the files, the element function is also used here. A pointer to is passed as the first parameter. The function works with the classic C strings. The second parameter is the maximum number of characters that can fit in the buffer.

[Reading a file]

#include #include using namespace std; int main (int argc, char * argv []) {fstream f; char cstring [256]; f.open (argv [1], ios :: in); while (! f.eof ()) {f.getline (cstring, sizeof (cstring)); cout << cstring << endl; } f.close (); }

There is also a global function called an object of the type ifstream has as the first parameter. This global function also works with the standard class string and accepts an object of this class as a second parameter. The example above would look like this:

[Reading a file (getline.cpp)]

#include #include #include using namespace std; int main (int argc, char * argv []) {ifstream f; // file handle string s; f.open (argv [1], ios :: in); // Open file from parameter while (! F.eof ()) // As long as there is still data {getline (f, s); // read a line cout << s << endl; // show it on the screen} f.close (); // close the file again}

Data files

However, the data redirection method is less suitable for writing binary data. The functions and are used here. This means that fixed data blocks can be read and written. Objects are mostly used as main memory buffers for the data blocks. tdata data; fstream f (..., ios :: out | ios :: binary | ios :: in); f.write (& data, sizeof (data)); ... f.read (& data, sizeof (data));

With the call to the object Data written to a file from the current position. When you later call, the file becomes an object Data read.

Data buffer

A class that is used as a data buffer should of course also contain all the data. As soon as the class contains pointers, main memory addresses are saved to the data and not to the data itself. Such pointers cannot always be seen openly, but are sometimes hidden behind data types. For example, contains an object of the class string References to the character string, but not the character string itself. Accordingly, a classic C-string, i.e. a fixed array of, is more suitable for a file buffer than a string or a pointer to one.

example

The following test program saves the first parameter with which the program was called in the file test file. If the program is called without parameters, the name saved last is read from the file and displayed on the screen. The program is available in two versions. In the version in which a C-String to contain the data in tdata is used, it works fine. On the other hand, remove the comment characters from the variable definition for Data and comment out the previous variable definition, the data is stored in a stringObject filed because the class is now tStrDaten is used. The program fails because the string is no longer within the limits of tStrDaten and is therefore not written to the file.

[Test: save data structure (testfstr.cpp)]

#include #include using namespace std; #include // This class accepts the character string in the classic // char array and thus contains the data. class tDaten {public: void Set (char * para) {strncpy (data, para, sizeof (data)); data [sizeof (data) -1] = 0; } void Show () {cout << data << endl; } private: char data [255]; }; // The C ++ strings are used here. However, // an object of type string does not contain the actual data. class tStrDaten {public: void Set (char * para) {data = para; } void Show () {cout << data << endl; } private: string data; }; int main (int argc, char ** argv) {// tStrDaten data; // It doesn't work with that! tdata data; // This is how it works! // A file called testfile is opened fstream f ("testfile", ios :: out | ios :: binary | ios :: in); // Was a parameter passed when the call was made? if (argc> = 2) {data.Set (argv [1]); // store in data // store object in file f.write ((char *) & data, sizeof (data)); } // No argument? Then read out the file! if (argc == 1) {// read file content in object f.read ((char *) & data, sizeof (data)); Data.show (); // ... and display}}

Versions

Also, keep in mind that file structures are generally more durable than program versions. As soon as the structure of the file buffer is changed, the files written by the previous version of the program will no longer be readable. This becomes critical when the previous version has been sent to the customer. The user will expect that the old data structure can at least be read after an update. Each process [1] manages a position indicator for each open file. After opening, this pointer is by default at the beginning of the file and continues to move towards the end of the file by reading or writing. To change position, the class offers ifstream the function on. The class ofstream uses the function for this. This means that a data block can be read or written at any point in the file. To do this, a seek call is first sent and then read or written. The first parameter of the seek functions is the position that the file pointer should get. A second parameter can optionally be specified. This determines from which direction the new position should be calculated. The following constants can be there: [Position direction]
value importance
ios :: beg Seen from the beginning of the file
ios :: cur As seen from the current file position
ios :: end Seen from the end of the file

Positioning

The parameterless member functions and can be used to determine the current position of the file pointer.

Empty buffer

File access is significantly faster if the operating system does not immediately write all data to the hard disk, but buffers it in main memory until several blocks can be written at once in one go. This behavior is standard on all systems today. Sometimes, however, the data record should be written to the disk immediately. This is done by calling the member function of the class fstream forced.

Condition monitoring

When working with files, various problems can arise for which the program should be prepared. A file that the program wants to read might not exist or be shorter than expected. While writing, the write authorization could be missing or the disk could be full.

good ()

The stream object can be asked at any time with the member function whether errors were found during the last action. The function has no parameters and returns a Boolean value. Alternatively, the stream object itself can also be queried. If it contains a 0, this corresponds to the return value false the function. fstream file; ... if (file.good ()) {// Everything is great ... if (file) {// Also good

The following program opens a file, writes a record to it, goes back to the beginning of the file and then reads the previously written record. It checks every step immediately after it has been carried out.

fstream f ("test.dat", ios :: out | ios :: binary | ios :: in); if (! f.good ()) {cerr << "Error opening test.dat" << endl; } f.write (& data, sizeof (data)); if (! f.good ()) {cerr << "Error writing test.dat" << endl; } f.seekg (0, ios :: beg); f.read (& data, sizeof (data)); if (! f.good ()) {cerr << "Error reading test.dat" << endl; }

End of file

If the line with the Seek command is removed from the example, the subsequent read command would cause an error if the file was initially empty. Due to the write command, the file position pointer is at the end of the file. The following read command can no longer read enough data from the file to save the buffer variable Data to fill. This state is called EOF (End Of File). Reaching the end of the file is not a disaster. It is quite common to read a file record by record until the end of the file is reached. To distinguish the end of file from other errors, there is a separate function called. It supplies the return value until the end of the file has been exceeded. The following loop reads all the data in a file: while (! F.eof ()) {f.read (& data, sizeof (data)); } f.clear ();

Clear error bits

After an error has occurred, the function returns this error until the error status of the stream object has been reset by calling from. In the example above, this was done after the end of the loop. The loop was exited by an EOF.

fail ()

In addition to the end of the file, there is also the possibility that writing or reading fails because the call could not be processed to the desired extent. In such a case the membership function of yields fstream the value true back.

bath()

A fatal error can be caused by querying the member function of fstream to be established. After such an error occurs, further operations will fail.

Throw exceptions

Calling the member function of fstream you can specify which error states should trigger exception handling. The constants
  • ,
  • and
linked with a binary or (a vertical line). fstream file; file.exceptions (fstream :: eofbit | fstream :: failbit | fstream :: badbit); try {// ... file processing} catch (const fstream :: failure & e) {cout < "exception"="">< endl;="" cout="">< "grund:="" "="">< e.what()="">< endl;="" cout="">< "fehlernummer:="" "="">< e.code()="">< endl;="" }="" mit="" catch="" fangen="" sie="" die="" exception="" vom="" typ="" fstream::failure="" und="" k├Ânnen="" diese="" mit="" what="" nach="" einer="" fehlerbeschreibung="" und="" mit="" code="" nach="" einer="" fehlernummer="" fragen.="">

You can find more detailed information about exception handling elsewhere. The handling of the exceptions to fstream dealt with in a separate section.

File access according to ANSI-C

Files have not only existed since C ++ existed, so it stands to reason that C already provides functions for editing files. Many C ++ programmers started out with C, and this type of file handling is often found in C ++ programs as well. Knowledge of these file accesses is important if you are to expand or correct an older program. Newer programs should work with the fstream-Classes are written. The advantages of the new classes are:
  • The operations are checked for type safety.
  • You can use exception handling.
  • If you ostream and istream you can ensure that files are not accidentally written to files that have only been opened for reading during compilation.

Handles

Since C does not know any classes, files are accessed via a collection of functions. When you open the file, you get a so-called handle back. You must pass this value every time you access the file so that the operating system knows which file you are working with. With the ANSI-C functions, this handle is a pointer to the type FILE. The following example shows how a data record is written to a file and then read out again.

[File handling]

#include int main () {FILE * f; f = fopen ("test.dat", "rwb"); if (f) {fwrite (buffer, sizeof (buffer), 1, f); fseek (f, 0, SEEK_SET); fread (buffer, sizeof (buffer), 1, f); fclose (f); }}

Open and close

The file is opened by calling and closed by calling. The functions have the following prototypes: FILE * fopen (const char * filename, const char * mode); int fclose (FILE * file handle);

The first parameter of is the filename. The second parameter is the opening mode, which is transferred as a string of one or more letters. Table (tab file mode) shows an overview. [Opening modes with fopen ()]

character importance
r Open to read
w Empty the file and open it for writing
a Data is appended
r + Allow writing as well as reading
w + Empty the file and open it for writing and reading
b Binary file (no conversion of the end-of-line characters)

Read and write

The function writes a data block to the file. The function reads a data block from the file. The functions have the following prototypes: size_t fread (void * buffer, size_t size, size_t n, FILE * f); size_t fwrite (void * buffer, size_t size, size_t n, FILE * f);

parameter

The first parameter is a pointer to the buffer in which the data is in main memory. Since the parameter type is a pointer to, the address can be transferred to any memory structure. The next two parameters describe the size of the buffer. First the size of each block is given, then the number of blocks. If data files are used whose buffer is a data structure, the parameter Size typically determined by one of the class and the number n set to 1. If, on the other hand, a text file is processed, it makes sense to Size to set to 1 and the number n set to the desired buffer size. The return value of both functions is the number of blocks that could actually be processed. Right n so does not match the return value, something has gone wrong. The last parameter is the file handle.

Text files

If you are working with text files, there are two special functions that are a little easier to use for this purpose: and. The function reads a line of text into a buffer. The length is limited by a parameter in order to avoid a buffer overflow. The function writes a character string to the file. The length is limited by a 0, as is usual with C strings: char * fgets (char * buffer, int size, FILE * f); char * fputs (char * buffer, FILE * f);

With the function it is possible to write the data to a file in formatted form. Apart from the file handle, the parameters correspond exactly to the function.

char * fprintf (FILE * f, char * format, ...);

Positioning

The file position pointer can be moved with this function. With the C files, there is only one common position indicator for reading and writing. int fseek (FILE * f, long offset, int RelPos);

The first parameter is the file handle, the second is the distance, and the third is a constant that describes what the distance refers to.

[fseek (): relative position]

constant importance
SEEK_SET From the beginning of the file
SEEK_CUR From the current position
SEEK_END From the end of the file

End Of File

The function determines whether the end of the file has been reached. The function has the file handle as the only parameter. The return value is 0 if the end of the file was not reached. int feof (FILE * f);

File system commands

The following calls are part of the ANSI standard for C and C ++ and enable the program to handle the file system in a basic way.

Delete file: remove

The function deletes the file whose name is passed to it as a parameter. #include int remove (const char * filename);

The global variable errno

The function returns 0 on success and -1 on failure. The cause of the error is in the variable errno. Most system calls return a value less than 0 if something goes wrong. If the return value is not meaningful enough, the cause of the error is in the global variable errno coded. The constants that errno can assume are in the header file errno.h to disposal. For example, one of the following constants can be used in the variable when calling errno to be found: [error constants]
constant importance
EACCES Lack of write authorization
ENOENT This file does not exist.
EROFS The file is on a write-protected medium.

Rename: rename

The function for renaming files is called. Under UNIX, this function can also be used to move files within the same file system. #include int rename (const char * filename, const char * nine name);

The function returns 0 on success and -1 on failure. The cause of the error is in the variable errno.

More functions

The commands for handling directories are unfortunately not part of the ANSI standard. They are always available under UNIX and standardized according to POSIX [2]. Many compilers also support them under Windows. For this reason, the keywords are listed here which you need to look up in the help of your compiler whether the functions are supported. Under UNIX you enter the command followed by the function and receive the prototype and the description of the function. [Directory functions]
function effect
mkdir Creates a directory
chdir Changes the directory
rmdir Deletes an empty directory
opendir Opens a directory to search for files
readdir Reads the next entry in the directory
closedir Closes the directory again

directory

Reading out a directory is not covered by the ANSI standard, but at least by POSIX. This standard for UNIX is also implemented by some C compilers. Since reading out directories is required again and again, it should be treated at least briefly. Here is a small program that prints all the file names in a directory on the screen.

[Reading a directory (dir.cpp)]

#include #include using namespace std; int main () {DIR * hdir; struct dirent * entry; hdir = opendir ("."); do {entry = readdir (hdir); if (entry) {cout << entry-> d_name << endl; }} while (entry); closedir (hdir); }

The pointer on TO YOU is the required handle to the directory. The function receives the directory name as a parameter. With some compilers it was difficult to read directories other than the current directory. You should test this with your compiler. After opening the directory, the function either returns a pointer to a variable in the directory entry structure dirent or a 0 if there is no further entry in the directory. Finally, the directory is closed again. The only element of guaranteed in the POSIX standard dirent is the file name under d_name. However, this is also sufficient, because further information can be determined via the name, for example with the function.

Determine file properties

The UNIX system call has also been ported to other systems with the C library. However, this function is not part of the ANSI standard. With this call information about files can be obtained. The function call is always available under UNIX. The Borland compilers and of course the GNU compilers mean it by Windows. Visual C ++ offers the call under the name.

stat ()

You can use the and fstat () functions to get information about a file. The results are stored in a structure of type [3]. You have to create a variable of this type and transfer its address to the function. The function has the following prototype: #include #include int stat (char * filename, struct stat * buffer);

The results are in the variable of type statto which the parameter buffer shows. The definition of the structure includes the following elements:

struct stat {dev_t st_dev / * (P) Device on which the file is located * / ushort st_ino / * (P) i-node number * / ushort st_mode / * (P) file type * / short st_nlink / * (P) Number of links in the file * / ushort st_uid / * (P) Owner user ID (uid) * / ushort st_gid / * (P) Group ID (gid) * / dev_t st_rdev / * Major and minor number, if device * / off_t st_size / * (P) Size in bytes * / time_t st_atime / * (P) Time of last access * / time_t st_mtime / * (P) Time of last change * / time_t st_ctime / * (P) Time of last status change * / };

The components of this structure can differ depending on the system. The elements marked with (P) are mandatory under UNIX by POSIX.

st_dev and st_ino
Under UNIX, st_dev and st_ino clearly describe the location of a file. st_dev is the device, i.e. the partition for hard disks. st_ino denotes the i-node, a UNIX unique identification number for files in a partition. Under Windows, the number of the drive is stored in st_dev. st_ino is always 0.
st_mode
The right twelve bits of st_mode describe whether the program can write, read or execute the file. Under UNIX, this information can be used to distinguish the rights for users, groups and the rest of the world. Table describes how the right nine bits of st_mode encode the rights. [4] [Rights for a file]
user group world
Read 4 4 4
Write 2 2 2
To run 1 1 1
The user rights can be evaluated under Windows. They provide information as to whether the file can be written and read. Windows uses the file extension to determine whether the file can be executed and makes this information available in st_mode. The next four bits encode the type of file. The constant S_IFMT is used to separate the two. You can use it to set a mask over these bits. You can then compare the value with the following constants: [Constants for the file type]
constant File type
S_IFSOCK Sockets
S_IFLNK Symbolic links
S_IFREG Regular files
S_IFBLK Block devices
S_IFDIR Directories
S_IFCHR Char devices
S_IFIFO FIFOs
The following example program determines the rights for the file transferred as the first parameter and then determines whether it is a file, a symbolic link (symbolic links are a special feature of the UNIX file systems that do not exist under MS Windows) or is a directory.

[Determine file type and rights]

#include #include int main (int argc, char ** argv) {struct stat status; int file type; stat (argv [1], & status); printf ("File rights:% o \ n", Status.st_mode & ~ S_IFMT); File type = Status.st_mode & S_IFMT; switch (file type) {case S_IFREG: puts ("file"); break; case S_IFLNK: puts ("Symbolic Link"); break; case S_IFDIR: puts ("directory"); break; default: puts ("Other"); }}

The constants S_IFREG (regular files) and S_IFDIR (directories) are also supported under Windows. This means that files and directories can be differentiated. The other file types are unknown to Windows.

st_nlink
St_nlink tells you how many hard links point to the file. Since Windows cannot create links, this value is always 1 there.
st_uid and st_gid
The owner and owner group are determined with st_uid and st_gid. The value is a number, namely the one that is in the file / etc / passwd or in / etc / group is determined. Under Windows, this is always 0.
st_rdev
The major and minor numbers are encoded in st_rdev if the file is a device. The drive number is shown here under Windows.
st_size
If the file is a regular file, you will find the size in bytes in st_size.
st_atime, st_mtime and st_ctime
Every read or write access to the file updates the st_atime value. Every change to the file content is noted in st_mtime. The time of changes by the user, the rights, the number of links or the like (i.e. everything that does not affect the content) is recorded in st_ctime.


[1]
A process is a program that has been started. If a program is started several times, several processes of the same program run.
[2]
POSIX (Portable Operating System Interface) is a family of standards for UNIX interfaces that have been bindingly established by the IEEE (Institute for Electrical and Electronic Engineers).
[3]
The structure is also called under Visual C ++ _stat.
[4]
The missing bits are extremely UNIX-specific.