Write to a text file

To write to a text file is not different from writing to std::cout. Recall that the program outputs sequences of characters (bytes) to the buffer of the stream connected to the file. The characters in the stream’s buffer are then automatically transferred to the text file.

We give an example of a program that requests a list of product items (name, quantity, and price) to the user and then, it writes them to a text file.

Streams

The function void write_product(std::ofstream& file, const Product& p); writes a given product p to a file. Note that a file stream argument of type std::ofstream is passed to the function by reference. It’s not possible to copy streams and, consequently, call-by-value cannot be used with stream arguments.

Required programming practice: use call-by-reference when passing streams as function arguments.

If an attempt is made to use call-by-value for a stream argument (as in void write_product(std::ofstream file, const Product& p);) then the compiler gives an ugly error. Just try it! It’s easy to use call-by-value in a stream argument of a function, after all it’s enough to miss one single character, the ampersand &, in the function’s parameter list. Thus, it’s important that you are acquainted with this compiler error and are able to recognize it quickly.

#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>

struct Product {
    std::string name;
    int quantity = 0;
    double price = 0.0;
};

// Read a product's data from std::cin
// Return a product with the data read
Product read_product();

// Write a product p to file
void write_product(std::ofstream& file, const Product& p);

int main() {
    std::ofstream utFil("C:/Expenses/list.txt");

    if (utFil) {  // succeeded to connect the stream utFil to the text file
        // Write file's header
        utFil << std::setw(20) << "Product" 
              << std::setw(14) << "Quantity" 
              << std::setw(10) << "Price"  << "\n";

        Product item = read_product();  // read first product

        // If it wasn't possible to read from std::cin then cin is in bad state
        // Loop until user ends input with ctrl-Z
        while (std::cin) {
            // write product to the text file
            write_product(utFil, item);

            item = read_product();  // read next product
        }
    } else {
        std::cout << "File could not be created!!\n";
    }
}

// Read a product's data from std::cin
// Return a product with the data read
Product read_product() {
    Product p;

    // Ask a product's name
    std::cout << "Product? ";
    std::cin >> std::ws;  // skip any white spaces before the name -- leading white spaces
    std::getline(std::cin, p.name);

    // Ask quantity and price
    std::cout << "Quantity and price? ";
    std::cin >> p.quantity >> p.price;

    return p;
}

// Write a product p to file
void write_product(std::ofstream& file, const Product& p) {
    // write product, quantity, and price to the text file
    file << std::setw(20) << p.name 
         << std::setw(10) << p.quantity 
         << std::setw(14) << std::fixed << std::setprecision(2) << p.price << '\n';
}

Note how the use of the function read_product(), which is called twice in the main, helps to avoid that the same code to read a product’s data appears repeated twice in the program.