Skip to content

Commit bb53e86

Browse files
committedApr 9, 2022
update readme with content
1 parent 58ec8f8 commit bb53e86

File tree

1 file changed

+223
-13
lines changed

1 file changed

+223
-13
lines changed
 

‎README.md

Lines changed: 223 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,233 @@
11
# File Handling in C++
22

3-
File handling is the crucial thing in any programming language that is used to restore the state of the program after restart. This repository contains the source code for the comprehensive guide on C++ file handling that you can find on [dev.to](https://dev.to/tbhaxor/a-comprehensive-guide-to-file-handling-in-c-59ge)
3+
You have been working with data in the program and struggling with saving its states across multiple restarts. Yeah, I know that is temporary and will be gone as the program exists. In this post, I will teach you how you can use C++ file handling and save not only text data into it but also binary data like Class or Struct.
44

5-
## Topics Covered
5+
You can clone the repository for all the snippets and source code used in this tutorial https://github.com/tbhaxor/cpp-file-handling-tutorial.
6+
7+
8+
## Why do you need File Handling Anyway?
9+
10+
The program state gets vanished when it is exited or the functions go out of scope during execution. Sometimes it's required to have the states for future execution.
11+
12+
Take the example of a game, you don't play it continuously. Saving the same and loading it later is very basic. I had first seen this in the Project IGI game and then Age of Empires. Nowadays multiplayer games are getting popular and they use databases to store this information.
13+
14+
That's a great idea to use databases. So why not use the database, it can be shared easily. Let me tell you that there is no different magic going on there, DBMS uses files to store the data. So it boils down to file handling.
15+
16+
17+
## Getting Started with File Handling
18+
19+
There are and will be 2 types of operation in the file: Read file will allow you to retrieve the content and write file will allow you to put the content into the file using the current stream. A stream is basically a channel that carries your data from/to the file.
20+
21+
[`std::ifstream`](https://www.cplusplus.com/reference/fstream/ifstream/) class is used to open the file in reading mode and [`std::ofstream`](https://www.cplusplus.com/reference/fstream/ofstream/) is used to open the file in the write mode.
22+
23+
These classes provide different methods and properties as an abstraction to deal with files, or I would say even the large files.
24+
25+
### Text File vs Binary File
26+
27+
There are two types of files: Human readable (or text) and human non-readable (binary).
28+
29+
It is easy to determine whether a file is a text or binary: If you open a file in a text editor (let's assume notepad or vscode), it will show all the characters and you can pronounce them. They might or might not make sense, but it's not required here. This file is a **text file**. If you are unable to pronounce any character, then that file is a **binary file**.
30+
31+
32+
> **Note** A binary file can contain a few readable characters as well, and that is ok.
33+
34+
|Text File|Binary File|
35+
|:----:|:----:|
36+
|![Text File](https://i.imgur.com/styO2fJ.png)|![Binary File](https://i.imgur.com/lqVstpt.png)|
37+
38+
### What is EOF
39+
40+
While seeing the file format and the number of total bytes, we can determine that there are {% katex inline %} n {% endkatex %} bytes in the file that can be read, but how does an opened stream will know in general? EOF is also known as [End-of-File](https://en.wikipedia.org/wiki/End-of-file) in computing. It is a condition or a notification to the file reader that tells no more retrieve more information from the file and seems like it is ended.
41+
42+
When you try to read a file and it is failed, both _failed_ and _eof_ bits are set in the error flags. You can use [`.eof()`](https://www.cplusplus.com/reference/ios/ios/eof/) method to get this information.
43+
44+
So when does this bit set? An EOF bit is set after the ifstream reader tried to read the contents from the file and fails while the stream is still good (there is no error while performing I/O operations). So at least in the case of an ifstream, it waits for the OS to tell it that there's no more data <sup>[read more](https://www.reddit.com/r/cpp_questions/comments/ty1hiz/comment/i3ppceo/?utm_source=share&utm_medium=web2x&context=3)</sup>
45+
46+
> This is not only used for files but also streams and sockets
47+
48+
Programmatically, it will look like the following
49+
50+
```cpp
51+
std::cout << ifile->bad() << " " << ifile->eof() << " "
52+
<< ifile->fail();
53+
54+
// 0 1 1
55+
```
56+
57+
## Writing into the File
58+
59+
Enough talking, let's start by writing a text content into the file using `std::ofstream`. Before all of that, you need to instantiate the ofstream and open the file:
60+
61+
```cpp
62+
std::ofstream *file = new std::ofstream();
63+
file->open("file.txt", std::ios::out);
64+
```
65+
66+
> You can use `std::ofstream file; // w/o pointer` as well, but I prefer pointers.
67+
68+
The [`.open()`](https://www.cplusplus.com/reference/fstream/ifstream/open/) function, as it says, open the file with name (_first argument_) and the mode (_second argument_).
69+
70+
I will discuss different modes with you as we proceed, `std::ios::out` mode is used to tell the function, that opens the file in write mode, overwrite the contents of it if it exists or create a new one.
71+
72+
Now it's time to write into the file stream using the left shift operator [`<<`](https://www.cplusplus.com/reference/ostream/ostream/operator%3C%3C/). This will format all your data into `char*` before writing.
73+
74+
```cpp
75+
(*file) << "Hello World" << std::endl;
76+
```
77+
78+
Since we are using a pointer variable, therefore it is required to dereference the file handle to access the `<<` operator from the `std::ofstream` object stored.
79+
80+
## Reading from the File
81+
82+
Reading is pretty simple and uses `std::ifstream` and `>>` operator with `std::ios::in` mode.
83+
84+
```cpp
85+
std::ifstream *file = new std::ifstream();
86+
file->open(argv[1], std::ios::in);
87+
```
88+
89+
For reading files in text mode, there is only one option [`std::ios::in`](https://www.cplusplus.com/reference/ios/ios_base/openmode/?kw=openmode)
90+
91+
```cpp
92+
std::string data;
93+
(*file) >> data;
94+
std::cout << data << std::endl; // Hello\n
95+
```
96+
97+
98+
### Reading until line end (eol)
99+
100+
When you write a file with `<<` it formats whitespaces and streams that to the file, but while reading the content, it will stop at either EOF or the first whitespace character hit.
101+
102+
EOL or End-of-line is defined by the character `\n` or `\r\n` and is considered as the whitespace. So if there are multiple lines, you can use the [`std::getline()`](https://www.cplusplus.com/reference/string/string/getline/) function.
103+
104+
```cpp
105+
std::getline(*file, data);
106+
std::cout << data << std::endl; // Hello World\n
107+
```
108+
109+
## Check Whether the File is Open or Not
110+
111+
Till now we are believing that the file exists and is ready for any I/O operation, but what if the condition is otherwise? What if it failed to open? Will it throw an error?
112+
113+
The answer to the question is, **NO**. It will not throw error but the RW will not work. You can use [`std::ifstream::is_open()`](https://www.cplusplus.com/reference/fstream/ifstream/is_open/) or [`std::ofstream::is_open()`](https://www.cplusplus.com/reference/fstream/ofstream/is_open/). The functions returns boolean value, so if the file is actually opened successfully, it will return true.
114+
115+
```cpp
116+
if (file->is_open()) {
117+
// do the rest actions here
118+
} else {
119+
std::cout << "Unable to open file\n";
120+
}
121+
```
122+
123+
## Closing file handle
124+
125+
When you are done with the file operations, it is recommended to close the file handle which will dispose of the file stream after writing any pending sequence of characters and clearing the buffer for both input and output streams.
126+
127+
For this you can use [`std::ofstream::close()`](https://www.cplusplus.com/reference/fstream/ofstream/close/) or [`std::ifstream::close`](https://www.cplusplus.com/reference/fstream/ifstream/close/).
128+
129+
```cpp
130+
file->close();
131+
```
132+
133+
If the file is not successfully opened, the function will fail and set the `failbit` flag.
134+
135+
## Appending into the Existing File
136+
137+
What if you want to append the data into the file without losing old content. In the `ios::out`, it overwrites the file and reading the content of files, appending in memory and then writing to a file doesn't seem to be a space and time-efficient solution.
138+
139+
There is another mode of opening the file that you can use in place of `ios::out`, which is append mode `ios::app`. This will allow you to write from the end of the file to the size of the data.
140+
141+
When you choose to open the file with append mode, the put cursor of the handle is set at the end of the file.
142+
143+
```cpp
144+
file->open(argv[1], std::ios::app);
145+
```
146+
147+
## Storing Class Object in the File
148+
149+
So far you have seen me dealing with the text file, but in the real world, there are more than binary files with the custom format, like Zip archives, PDF files and other document files.
150+
151+
To open the file in binary mode, you need to specify `std::ios::binary` mode in the `open()` method of `std::ifstream` or `std::ofstream`.
152+
153+
```cpp
154+
in_file->open("file.bin", std::ios::binary | std::ios::in);
155+
156+
out_file->open("file.bin", std::ios::binary | std::ios::out);
157+
```
158+
159+
For reading and writing, you must use [`std::ifstream::read()`](https://www.cplusplus.com/reference/istream/istream/read/) and [`std::ofstream::write()`](https://www.cplusplus.com/reference/ostream/ostream/write/) because the binary file saves the raw bytes and does not perform any kind of formatting.
160+
161+
With this, you can now store the object of structs or classes directly into the file without serializing it into the textual format. It will be then automatically deserialized when the file is read.
162+
163+
Let's create a simple class called `Student` that will have _name_ and _age_ fields and a _whoami()_ method to return a std::string object.
164+
165+
```cpp
166+
class Student {
167+
private:
168+
std::string name;
169+
unsigned short age;
170+
public:
171+
Student() {
172+
this->name = ""
173+
this->age = 0;
174+
}
175+
176+
Student(const char * name, unsigned short age) {
177+
this->name = std::string(name);
178+
this->age = age;
179+
}
180+
181+
std::string whoami() const {
182+
std::stringstream s;
183+
s << "I am " << this->name << " and " << this->age << " years old";
184+
return s.str();
185+
}
186+
187+
};
188+
189+
Student student("Gurkirat Singh", 20);
190+
```
191+
192+
You can save this to a file using the following snippet by casing it to `char*` because of its definition in the stdc++. <sup>[read more](https://stackoverflow.com/a/45202852/10362396)</sup>
193+
194+
```cpp
195+
out_file->write(reinterpret_cast<char*>&student, sizeof(student));
196+
```
197+
198+
Once this is successfully saved into the file, you will verify that there are some weird characters present in the file and that is normal, because the string data also stores the information of deserializing the object.
199+
200+
```cpp
201+
Student mystudent;
202+
in_file->read(reinterpret_cast<char*>&mystudent, sizeof(mystudent));
203+
204+
std::cout << mystudent.whoami() << std::endl; // I am Gurkirat Singh and 20 years old
205+
```
206+
207+
Now as a beginner, you must be thinking that the `Student` type is different from the `char` type. So why does the casting pointer not affect serialization? I would like to tell you that, you are getting confused between pointer type and other data types. For any data type, the pointer type would be 8 bytes or 4 bytes based on the CPU architecture, because it stores the starting address of the memory where that actual data of a type is stored. If the type of data is char, then it will consume 1 byte in the memory otherwise `sizeof(T)`.
208+
209+
## Using I/O Streams of the File
210+
211+
It is not like you can open a file only in one mode (that is either read or write), using `std::fstream` you can perform both input/output operations on the file with the same file handle.
212+
213+
### Read/Write Cursors
214+
215+
There are two types of cursors in the file **`g`**et and **`p`**ut. The get cursor is responsible for handling reading from the file which is known as **input operation** and the put cursor is responsible for handling writing into the file which is known as **output operation**.
216+
217+
To **get** the current position of the cursors, use the [`std::fstream::tellp()`](https://www.cplusplus.com/reference/ostream/ostream/tellp/?kw=tellp) or [`std::fstream::tellg()`](https://www.cplusplus.com/reference/istream/istream/tellg/?kw=tellg). You can also set the position of these cursors making (either forward or backward) while the file is open using [`std::fstream::seekp()`](https://www.cplusplus.com/reference/ostream/ostream/seekp/?kw=seekp) or [`std::fstream::seekg()`](https://www.cplusplus.com/reference/istream/istream/seekg/?kw=seekg) functions.
218+
219+
You can also seek the cursor relatively based on the three types of the [seek directions](https://www.cplusplus.com/reference/ios/ios_base/seekdir/)
220+
221+
+ `std::ios::beg` &mdash; from the beginning of file
222+
+ `std::ios::cur` &mdash; from the current position of the cursor
223+
+ `std::ios::end` &mdash; from the ending of the file or where the reader hits EOF
224+
225+
> **Note** You must clear the flags using [`std::fstream::clear()`](https://www.cplusplus.com/reference/ios/ios/clear/) to clear all the error bits before using `seekg()` or `seekp()`. <sup>[read more](https://stackoverflow.com/questions/16364301/whats-wrong-with-the-ifstream-seekg)</sup>
6226
7-
1. Why you need File Handling Anyway?
8-
2. Getting Started with File Handling
9-
1. Text File vs Binary File
10-
2. What is EOF
11-
3. Writing into the File
12-
4. Reading from the File
13-
5. Check Whether the File is Open or Not
14-
6. Appending into the Existing File
15-
7. Storing Class Object in the File
16-
8. Using I/O Streams of the File
17227
18228
## Contact Details
19229
20-
Email: tbhaxor _at_ gmail _dot_ com
230+
Email: tbhaxor _at_ proton _dot_ me
21231
22232
Twitter: @tbhaxor
23233

0 commit comments

Comments
 (0)