Binary files are files that store data in a format that is directly readable by the computer, as opposed to human-readable formats like text files. These files are typically used for storing more complex data types, such as images, audio files, and custom objects, as they store raw binary data rather than text.
A file is considered binary if it contains data in a format that represents values directly in memory, rather than encoding them as text. In other words, a binary file stores the raw, machine-level representation of data. This is different from text files, where data is stored as characters (ASCII, UTF-8, etc.).
For example:
| Feature | Text Files | Binary Files |
|---|---|---|
| Data Representation | Characters encoded as text (e.g., ASCII, UTF-8). | Raw data represented by bytes (e.g., integers, floats). |
| Human Readability | Easily readable by humans. | Not human-readable; requires a program to interpret the data. |
| File Size | Usually larger, due to encoding overhead (e.g., storing a 4-byte integer as 4 ASCII characters). | Typically smaller, as data is stored as raw binary. |
| Line Breaks | Stores line breaks explicitly (e.g., \n). | Line breaks are not explicitly stored. |
| Efficiency | Slower for reading/writing complex data types. | More efficient for reading and writing large or complex data. |
| Error Handling | Errors in encoding or format are easily noticeable (e.g., invalid characters). | Errors can be harder to detect unless using specific tools. |
To work with binary files, you need to use the ifstream (input file stream) and ofstream (output file stream) classes in C++, but in binary mode. This allows you to read and write raw binary data, such as integers, floats, and complex structures, directly to and from a file.
Here’s how you can open files in binary mode:
ifstream infile("example.bin", ios::binary); // Open for reading in binary mode
ofstream outfile("example.bin", ios::binary); // Open for writing in binary mode
To read or write binary data, we use the read() and write() methods of the stream classes. These methods read or write a specified number of bytes from the file.
Here’s an example of writing a single integer and a floating-point number to a binary file:
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ofstream outfile("example.bin", ios::binary); // Open file in binary mode
if (!outfile) {
cout << "Error opening file!" << endl;
return 1;
}
int number = 42;
double pi = 3.14159;
// Write the data to the file in binary format
outfile.write(reinterpret_cast<char*>(&number), sizeof(number));
outfile.write(reinterpret_cast<char*>(&pi), sizeof(pi));
outfile.close();
return 0;
}
In this example:
reinterpret_cast<char*>(&number): Converts the pointer to number into a char*, as the write() method requires a pointer to char for reading raw bytes.sizeof(number): Specifies how many bytes to write.To read the binary data back, you can use the read() method:
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ifstream infile("example.bin", ios::binary); // Open file in binary mode
if (!infile) {
cout << "Error opening file!" << endl;
return 1;
}
int number;
double pi;
// Read the data from the file
infile.read(reinterpret_cast<char*>(&number), sizeof(number));
infile.read(reinterpret_cast<char*>(&pi), sizeof(pi));
cout << "Number: " << number << endl;
cout << "Pi: " << pi << endl;
infile.close();
return 0;
}
In this case, we read the binary data from the file into the variables number and pi. The read() method takes a pointer to the variable where data should be stored, and the number of bytes to read (which is determined using sizeof()).
You can also read and write complex data types like objects and structures to binary files. To do this, you need to treat the object as raw memory (just like with primitive types).
Here’s how to write a structure to a binary file:
#include <iostream>
#include <fstream>
using namespace std;
struct Person {
string name;
int age;
};
int main() {
Person p = {"Alice", 30};
ofstream outfile("person.bin", ios::binary);
if (!outfile) {
cout << "Error opening file!" << endl;
return 1;
}
// Write the structure to the binary file
outfile.write(reinterpret_cast<char*>(&p), sizeof(p));
outfile.close();
return 0;
}
In this case, we write the entire structure p to the file as raw bytes.
To read the structure back, we use the read() method:
#include <iostream>
#include <fstream>
using namespace std;
struct Person {
string name;
int age;
};
int main() {
Person p;
ifstream infile("person.bin", ios::binary);
if (!infile) {
cout << "Error opening file!" << endl;
return 1;
}
// Read the structure from the binary file
infile.read(reinterpret_cast<char*>(&p), sizeof(p));
cout << "Name: " << p.name << endl;
cout << "Age: " << p.age << endl;
infile.close();
return 0;
}
Note: One thing to keep in mind is that writing complex types (like string or dynamically allocated data) as raw binary can lead to problems because these types contain pointers, which are platform-dependent. A safer approach would be to serialize the data (i.e., manually writing each element of the structure) instead of using raw binary writes.