Loading...

Go Back

Next page
Go Back Course Outline

C++ Full Course


File I/O & Serialization in C++

File I/O & Serialization in C++

File input/output (I/O) and serialization are fundamental aspects of many C++ applications, allowing programs to interact with files on the file system and to save and load the state of objects.

Streams

C++ uses streams to perform I/O operations. The <fstream> header provides classes for file streams:

  • std::ifstream: Used for reading data from files (input file stream).
  • std::ofstream: Used for writing data to files (output file stream).
  • std::fstream: Used for both reading from and writing to files (file stream).
#include <iostream>
#include <fstream>
#include <string>

int main() {
    // Writing to a text file
    std::ofstream outputFile("example.txt");
    if (outputFile.is_open()) {
        outputFile << "This is a line of text.\n";
        outputFile << "Another line here.\n";
        outputFile.close();
        std::cout << "Data written to example.txt" << std::endl;
    } else {
        std::cerr << "Unable to open file for writing." << std::endl;
    }

    // Reading from a text file
    std::ifstream inputFile("example.txt");
    std::string line;
    if (inputFile.is_open()) {
        std::cout << "\nContents of example.txt:\n";
        while (getline(inputFile, line)) {
            std::cout << line << std::endl;
        }
        inputFile.close();
    } else {
        std::cerr << "Unable to open file for reading." << std::endl;
    }

    return 0;
}
Data written to example.txt

Contents of example.txt:
This is a line of text.
Another line here.


Binary vs. Text Files

Files can be treated as either text or binary. The way data is read from and written to these types of files differs.

Text Files

Text files store data as sequences of characters that are human-readable. Operations on text files often involve formatting and interpretation of data as strings.

The previous example with ofstream and ifstream demonstrates text file I/O.

Binary Files

Binary files store data in its raw, unformatted form as sequences of bytes. This can be more efficient for storing complex data structures without the overhead of text-based representation. Reading and writing binary data involves working directly with blocks of memory.

#include <iostream>
#include <fstream>
#include <vector>

struct Data {
    int id;
    double value;
};

int main() {
    // Writing binary data
    std::ofstream binaryOutputFile("data.bin", std::ios::binary);
    if (binaryOutputFile.is_open()) {
        Data dataToWrite = {123, 3.14159};
        binaryOutputFile.write(reinterpret_cast<const char*>(&dataToWrite), sizeof(dataToWrite));
        binaryOutputFile.close();
        std::cout << "Binary data written to data.bin" << std::endl;
    } else {
        std::cerr << "Unable to open binary file for writing." << std::endl;
    }

    // Reading binary data
    std::ifstream binaryInputFile("data.bin", std::ios::binary);
    if (binaryInputFile.is_open()) {
        Data dataRead;
        binaryInputFile.read(reinterpret_cast<char*>(&dataRead), sizeof(dataRead));
        if (binaryInputFile.gcount() == sizeof(Data)) {
            std::cout << "\nBinary data read from data.bin:\n";
            std::cout << "ID: " << dataRead.id << ", Value: " << dataRead.value << std::endl;
        } else {
            std::cerr << "Error reading binary data." << std::endl;
        }
        binaryInputFile.close();
    } else {
        std::cerr << "Unable to open binary file for reading." << std::endl;
    }

    return 0;
}
Binary data written to data.bin

Binary data read from data.bin:
ID: 123, Value: 3.14159


Serialization Libraries

Serialization is the process of converting the state of an object into a format that can be stored (e.g., in a file or memory buffer) or transmitted across a network and then reconstructed later (deserialization). While you can implement serialization manually, using dedicated libraries can simplify the process, handle complex object relationships, and provide platform independence.

Boost.Serialization

Boost.Serialization is a powerful and widely used library for serializing C++ data structures. It supports various formats and handles complex scenarios, including pointers, inheritance, and versioning.

To use Boost.Serialization, you typically need to include the library headers and define a serialize method within your classes.


        // Example using Boost.Serialization (requires linking against the Boost.Serialization library)
        #include <fstream>
        #include <iostream>
        #include <boost/archive/text_oarchive.hpp>
        #include <boost/archive/text_iarchive.hpp>

        class MyData {
        public:
            int id;
            double value;

            template<class Archive>
            void serialize(Archive & ar, const unsigned int version) {
                ar & id;
                ar & value;
            }
        };

        int main() {
            // Serialization
            {
                std::ofstream ofs("boost_data.txt");
                boost::archive::text_oarchive oa(ofs);
                MyData dataOut = {456, 2.71828};
                oa & dataOut;
                std::cout << "Data serialized using Boost.Serialization." << std::endl;
            }

            // Deserialization
            {
                std::ifstream ifs("boost_data.txt");
                boost::archive::text_iarchive ia(ifs);
                MyData dataIn;
                ia & dataIn;
                std::cout << "Data deserialized using Boost.Serialization:\n";
                std::cout << "ID: " << dataIn.id << ", Value: " << dataIn.value << std::endl;
            }

            return 0;
        }
    

Note: This example requires the Boost library to be installed and linked during compilation.

nlohmann/json

nlohmann/json is a popular header-only library for working with JSON (JavaScript Object Notation) in C++. JSON is a lightweight data-interchange format that is easy for humans to read and write and easy for machines to parse and generate. It's often used for configuration files, data transfer in web applications, and serialization.

#include <fstream>
#include <iostream>
#include <nlohmann/json.hpp>

struct MyConfig {
    std::string serverAddress;
    int port;
    std::vector<std::string> users;

    void to_json(nlohmann::json& j) const {
        j = nlohmann::json{{"serverAddress", serverAddress}, {"port", port}, {"users", users}};
    }

    void from_json(const nlohmann::json& j) {
        j.at("serverAddress").get_to(serverAddress);
        j.at("port").get_to(port);
        j.at("users").get_to(users);
    }
};

int main() {
    // Serialization to JSON
    MyConfig configOut = {"localhost", 8080, {"alice", "bob", "charlie"}};
    nlohmann::json jsonConfigOut = configOut;
    std::ofstream jsonOfs("config.json");
    jsonOfs << jsonConfigOut.dump(4) << std::endl;
    std::cout << "Configuration serialized to config.json using nlohmann/json." << std::endl;

    // Deserialization from JSON
    std::ifstream jsonIfs("config.json");
    nlohmann::json jsonConfigIn;
    jsonIfs >> jsonConfigIn;
    MyConfig configIn = jsonConfigIn.get<MyConfig>();
    std::cout << "Configuration deserialized from config.json using nlohmann/json:\n";
    std::cout << "Server Address: " << configIn.serverAddress << std::endl;
    std::cout << "Port: " << configIn.port << std::endl;
    std::cout << "Users: ";
    for (const auto& user : configIn.users) {
        std::cout << user << " ";
    }
    std::cout << std::endl;

    return 0;
}

Note: This example requires the nlohmann/json library to be included in your project (often as a header-only library).

Choosing the right approach for File I/O and serialization depends on the specific requirements of your application, such as data format, performance needs, and complexity of the data structures.

Go Back

Next page