← Back to C++ Course | Chapter 15: File I/O | Lesson 4 of 6

C++ Binary Files

A binary file stores raw data exactly as the computer holds it, like taking a photo instead of describing it in words. It is compact but not human-readable.
Syntax
cpp
std::ofstream out("filename.bin", std::ios::binary);
out.write(reinterpret_cast<char*>(&variable), sizeof(variable));

std::ifstream in("filename.bin", std::ios::binary);
in.read(reinterpret_cast<char*>(&variable), sizeof(variable));

Writing Binary Data

Binary mode stores a variable's raw in-memory byte representation directly to disk, rather than converting it to human-readable text first.

Opening a stream with the ios::binary flag and calling write() with a pointer and byte count saves data exactly as it exists in memory -- faster and more compact than text output, but not human-readable.

Example: Writing Binary Data

cpp
// Include std::cout and std::cin
#include <iostream>
// Include file streams
#include <fstream>

// Program execution starts in main()
int main() {
	// Declare value and set it to 42
	int value = 42;
	std::ofstream file("data.bin", std::ios::binary);
	file.write(reinterpret_cast<char *>(&value), sizeof(value));
	file.close();
	// Print to the console with cout
	std::cout << "Binary data written" << std::endl;
	// Return 0 to signal that the program finished successfully
	return 0;
}

Reading Binary Data

read() is the binary counterpart to write() -- it copies a given number of bytes from the file directly into a variable's memory.

Because read() expects a char*, you must reinterpret_cast your variable's address to that type first, since C++ won't implicitly convert an int* or struct pointer to char*.

Example: Reading Binary Data

cpp
// Include std::cout and std::cin
#include <iostream>
// Include file streams
#include <fstream>

// Program execution starts in main()
int main() {
	// Declare value and set it to 42
	int value = 42;
	std::ofstream out("data.bin", std::ios::binary);
	out.write(reinterpret_cast<char *>(&value), sizeof(value));
	out.close();

	int readValue;
	std::ifstream in("data.bin", std::ios::binary);
	in.read(reinterpret_cast<char *>(&readValue), sizeof(readValue));
	// Print to the console with cout
	std::cout << readValue << std::endl;
	// Return 0 to signal that the program finished successfully
	return 0;
}

Binary vs Text Mode

Text mode may translate certain characters during I/O (such as converting newline conventions between operating systems), which would corrupt non-text data like an int or a struct.

Binary mode disables all such translation, transferring the exact bytes with nothing added or changed.

Example: Binary vs Text Mode

cpp
// Include std::cout and std::cin
#include <iostream>
// Include file streams
#include <fstream>

// Program execution starts in main()
int main() {
	// Declare pi and set it to 3.14159
	double pi = 3.14159;
	std::ofstream file("data.bin", std::ios::binary);
	file.write(reinterpret_cast<char *>(&pi), sizeof(pi));
	file.close();
	// Print to the console with cout
	std::cout << "Written in binary mode, no text translation" << std::endl;
	// Return 0 to signal that the program finished successfully
	return 0;
}

Writing/Reading Arrays of Structs

Because write()/read() work with a byte count, not element-by-element conversions, you can pass an entire array of structs in one call using sizeof(struct) * count -- this single bulk operation is dramatically faster than looping and writing one field at a time.

Example: Writing/Reading Arrays of Structs

cpp
// Include std::cout and std::cin
#include <iostream>
// Include file streams
#include <fstream>

// Define a structure type named Point
struct Point { int x, y; };

// Program execution starts in main()
int main() {
	Point points[2] = {{1, 2}, {3, 4}};
	std::ofstream file("data.bin", std::ios::binary);
	file.write(reinterpret_cast<char *>(points), sizeof(Point) * 2);
	file.close();
	// Print to the console with cout
	std::cout << "Wrote array of structs in one call" << std::endl;
	// Return 0 to signal that the program finished successfully
	return 0;
}

Random Access in Binary Files

Since every record in a binary file occupies a fixed, known number of bytes (sizeof(RecordType)), you can jump directly to the Nth record with seekg(N * sizeof(RecordType)) instead of reading through every record before it -- this is what makes random access to specific records practical.

Example: Random Access in Binary Files

cpp
// Include std::cout and std::cin
#include <iostream>
// Include file streams
#include <fstream>

// Define a structure type named Record
struct Record { int id; };

// Program execution starts in main()
int main() {
	Record records[3] = {{1}, {2}, {3}};
	std::ofstream out("data.bin", std::ios::binary);
	out.write(reinterpret_cast<char *>(records), sizeof(Record) * 3);
	out.close();

	std::ifstream in("data.bin", std::ios::binary);
	in.seekg(1 * sizeof(Record));
	Record r;
	in.read(reinterpret_cast<char *>(&r), sizeof(Record));
	// Print to the console with cout
	std::cout << r.id << std::endl;
	// Return 0 to signal that the program finished successfully
	return 0;
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Opening a binary file without ios::binary, so text translation can corrupt data on Windows.
  2. Writing objects that contain pointers, which stores addresses instead of data.
  3. Reading a different number of bytes than were written.
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.