English
Practice
Each complete example has its own main and is built in a separate console project. The input data is given directly in the program. Use x64, /std:c++latest, /EHsc, /W4, /utf-8, and /permissive-. After a build error, do not run the old executable.
Example 1. Simplified INI settings
Problem. Parse the given lines of the ui section, change theme, and write your own file.
cpp
#include <fstream>
#include <map>
#include <print>
#include <sstream>
#include <string>
int main()
{
std::istringstream input("[ui]\ntheme=light\nsize=14\n");
std::map<std::string, std::map<std::string, std::string>> data;
std::string section;
for (std::string line; std::getline(input, line);) {
if (line.empty()) continue;
if (line.front() == '[' && line.back() == ']') {
section = line.substr(1, line.size() - 2);
continue;
}
auto pos = line.find('=');
if (section.empty() || pos == std::string::npos
|| pos == 0) return 1;
data[section][line.substr(0, pos)] = line.substr(pos + 1);
}
data["ui"]["theme"] = "dark";
std::ofstream out("settings-demo.ini");
for (const auto& [name, entries] : data) {
out << '[' << name << "]\n";
for (const auto& [key, value] : entries)
out << key << '=' << value << '\n';
}
out.close();
if (!out) return 1;
std::println("theme: {}", data.at("ui").at("theme"));
}Output:
text
theme: darkThis is a limited format: there are no comments, escaping, multiline values, or whitespace trimming. A repeated key replaces the previous one. The data is generated by the program; for an external file, add an ifstream with an open check and the numbers of invalid lines. The resulting settings-demo.ini has a ui section with size=14 and theme=dark.
Example 2. A hexadecimal dump in blocks
Problem. Generate five bytes and read them in blocks of four without losing the short tail.
cpp
#include <array>
#include <fstream>
#include <print>
int main()
{
{
std::ofstream out("bytes-demo.bin", std::ios::binary);
const char bytes[]{0, 1, 15, 16, 127};
out.write(bytes, sizeof bytes);
out.close();
if (!out) return 1;
}
std::ifstream in("bytes-demo.bin", std::ios::binary);
if (!in) return 1;
std::array<char, 4> block;
while (in.read(block.data(), block.size()) || in.gcount()) {
for (std::streamsize i = 0; i < in.gcount(); ++i) {
auto b = static_cast<unsigned char>(block[i]);
std::print("{:02X} ", b);
}
}
std::println();
return in.bad() ? 1 : 0;
}Output:
text
00 01 0F 10 7FThe last read requests four bytes but gets one. The condition with gcount lets you process this tail. The conversion to unsigned char keeps a signed char from corrupting the values 128..255. After the loop ends, we check bad so as not to mistake a storage error for the normal end.
Example 3. A training backup copy
Problem. Create your own file and copy it if there is no copy or there is a sign of a change.
cpp
#include <filesystem>
#include <fstream>
#include <print>
#include <system_error>
namespace fs = std::filesystem;
int main()
{
fs::create_directories("backup-demo/source");
fs::create_directories("backup-demo/copy");
const fs::path source = "backup-demo/source/note.txt";
const fs::path target = "backup-demo/copy/note.txt";
{
std::ofstream seed(source);
seed << "training note\n";
seed.close();
if (!seed) return 1;
}
std::error_code ec;
bool exists = fs::exists(target, ec);
if (ec) return 1;
bool changed = !exists;
if (exists) {
auto size1 = fs::file_size(source, ec);
if (ec) return 1;
auto size2 = fs::file_size(target, ec);
if (ec) return 1;
auto time1 = fs::last_write_time(source, ec);
if (ec) return 1;
auto time2 = fs::last_write_time(target, ec);
if (ec) return 1;
changed = size1 != size2 || time1 > time2;
}
if (changed) {
fs::copy_file(source, target,
fs::copy_options::overwrite_existing, ec);
if (ec) return 1;
}
std::println("copy exists: {}", fs::exists(target));
}Output:
text
copy exists: trueThis copies one controlled file; it deletes nothing in the destination. Size and time do not prove byte-for-byte equality: a file of the same length with the same time may have different contents. A strong check requires comparing the contents or a suitable hash. The demonstration creates the source every time; after the first copy, check the contents of both files.