File I/O in C++

Table of Contents

ofstream in C++

std::ofstream (output file stream) is a C++ class used for writing data to files. Internally, an ofstream object owns a std::filebuf, which acts as the stream buffer responsible for performing the actual I/O operations on the associated file.

By default, when a file is opened usingstd::ofstream, it is opened instd::ios::out mode. If the file already exists, its contents are truncated, meaning all existing data is discarded before new data is written.

To preserve the existing contents of a file and write new data at the end, you can open the file using the std::ios::app flag. In this mode, all output operations automatically write to the end of the file. When working with non-text data, the std::ios::binary flag can be used to disable text-specific transformations and ensure data is written exactly as provided.

These file open modes can be combined using the bitwise OR operator |. For example, the following opens a file in append mode while writing raw binary data:

1std::ofstream outFile("data.bin", std::ios::app | std::ios::binary);

seekp

The seekp() function (seek put) moves the output stream's internal write pointer to a specific position within the file. This allows random-access writing, giving you control over where the next write operation will occur.

The new position is specified using an offset and a reference position. The reference position can be relative to the beginning of the file, the current write position, or the end of the file, as defined by std::ios_base::beg, std::ios_base::cur, and std::ios_base::end.

tellp

The tellp() function (tell put) returns the current position of the write pointer in the output file. The returned value is of type std::streampos and is often used to check whether a file is empty or to track how much data has already been written.

1CSVLogger(const std::string &filename)
2{
3    ofs_.open(filename, std::ios::out | std::ios::app);
4    // std::ios::out opens the file for writing
5    // std::ios::app ensures all writes go to the end of the file
6
7    if (!ofs_.is_open())
8    {
9        throw std::runtime_error("Unable to open log file: " + filename);
10    }
11
12    // Move the write pointer to the end of the file
13    ofs_.seekp(0, std::ios::end);
14
15    // If the file is empty, write the CSV header
16    if (ofs_.tellp() == 0)
17    {
18        ofs_ << "timestamp_ms,buy_order,sell_order,price,qty
19";
20    }
21}
22
23void log_trade(const Trade &t)
24{
25    std::lock_guard<std::mutex> g(mtx);
26
27    auto ms =
28        std::chrono::duration_cast<std::chrono::milliseconds>(
29            t.ts.time_since_epoch())
30            .count();
31
32    ofs_ << ms << ","
33         << t.buy_order << ","
34         << t.sell_order << ","
35         << t.price << ","
36         << t.qty << "
37";
38
39    ofs_.flush();
40}

flush

ofs.flush() forces all buffered output data to be written to the file immediately. Normally, output streams buffer data in memory and write to disk later for performance reasons.

Calling flush() is especially important for logging, auditing, or long-running programs, where you want to ensure data is safely persisted even if the program crashes or exits unexpectedly.

ifstream in C++

std::ifstream is the C++ input file stream used for reading data from files. It allows your program to treat a file as a stream of characters, similar to reading from std::cin, but with the data coming from disk instead of user input.

Before reading from a file, it is good practice to verify that the file was opened successfully. Once open, data can be read line by line, token by token, or byte by byte.

1#include <iostream>
2#include <fstream>
3#include <string>
4
5int main()
6{
7    std::ifstream inputFile("example.txt");
8
9    if (!inputFile.is_open())
10    {
11        std::cerr << "Error opening file!" << std::endl;
12        return 1;
13    }
14
15    std::string line;
16    while (std::getline(inputFile, line))
17    {
18        std::cout << line << std::endl;
19    }
20
21    inputFile.close();
22    return 0;
23}

seekg

seekg() moves the input stream's read pointer to a specific position in the file. This allows you to jump to different parts of a file instead of reading it sequentially from start to end.

You can move the pointer relative to the beginning, the current position, or the end of the file using std::ios_base::beg, std::ios_base::cur, and std::ios_base::end respectively.

1MyReadFile.seekg(6, std::ios_base::beg);
2std::cout << MyReadFile.tellg() << "\n";
3
4MyReadFile.seekg(-3, std::ios_base::cur);
5std::cout << MyReadFile.tellg() << "\n";
6
7MyReadFile.seekg(-4, std::ios_base::end);
8std::cout << MyReadFile.tellg() << "\n";

tellg

tellg() returns the current position of the read pointer in the file. This value represents how many bytes from the beginning of the file have already been read or skipped.

1std::cout << MyReadFile.tellg();