C++ provides robust file manipulation capabilities through the <fstream> library, which extends std::iostream with dedicated stream classes for persistent storage interaction. Core operations revolve around three primary classes: std::ifstream for input, std::ofstream for output, and std::fstream for combined access. Proper resource management dictates checking open states before execution and explicitly closing handles upon completion.
Stream Initialization and Mode Flags
Files are opened by passing filenames and optional mode flags to constructors or .open() methods. Common flags include std::ios::in (read), std::ios::out (write), std::ios::app (append to end), and std::ios::binary. Flags can be combined using bitwise OR. If a handle fails to initialize, the stream evaluates to false or .fail() returns true.
Word-Level Extraction and Redirection
This snippet demonstrates extracting whitespace-delimited tokens from a source file and redirecting them to a destination file. It utilizes standard string buffers and handles potential stream errors gracefuly.
#include <iostream>
#include <fstream>
#include <string>
int main() {
constexpr const char* source_path = "sample_input.dat";
constexpr const char* target_path = "processed_output.dat";
std::ifstream reader(source_path);
if (!reader.is_open()) {
std::cerr << "Failed to load source." << std::endl;
return 1;
}
std::ofstream writer(target_path, std::ios::trunc);
if (!writer.is_open()) {
std::cerr << "Failed to create target." << std::endl;
return 1;
}
std::cout << "Source content stream:" << std::endl;
std::string token;
while (reader >> token) {
std::cout << token << '\n';
writer << token << ' ';
}
writer << '\n';
reader.close();
writer.close();
std::cout << "Redirection complete." << std::endl;
return 0;
}
Structured Data Serialization and Recovery
Storing structured records requires careful type conversion. While pure C++ streams support formatted I/O, integrating legacy C functions like fwrite remains valid for specific binary layouts. The following implementation captures vehicle telemetry, converts integer payloads to strings, and persists them alongside textual identifiers.
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <string>
struct VehicleProfile {
char id_code[16];
char manufacturer[24];
double payload_mass_kg;
};
int main() {
VehicleProfile asset;
std::printf("Enter ID Code: ");
std::cin.getline(asset.id_code, sizeof(asset.id_code));
std::printf("Enter Manufacturer: ");
std::cin.getline(asset.manufacturer, sizeof(asset.manufacturer));
std::printf("Enter Payload Mass (kg): ");
std::cin >> asset.payload_mass_kg;
FILE* handler = std::fopen("telemetry_record.dat", "w");
if (!handler) {
std::perror("File creation failed");
return 1;
}
std::fwrite(asset.id_code, 1, std::strlen(asset.id_code), handler);
std::fputc('\n', handler);
std::fwrite(asset.manufacturer, 1, std::strlen(asset.manufacturer), handler);
std::fputc('\n', handler);
char mass_buffer[32];
std::snprintf(mass_buffer, sizeof(mass_buffer), "%.2f kg", asset.payload_mass_kg);
std::fwrite(mass_buffer, 1, std::strlen(mass_buffer), handler);
std::fclose(handler);
std::ifstream recovery("telemetry_record.dat", std::ios::in);
if (!recovery) {
std::cerr << "Recovery path inaccessible." << std::endl;
return 1;
}
std::string line_segment;
std::cout << "Recovered records:" << std::endl;
while (std::getline(recovery, line_segment)) {
std::cout << "> " << line_segment << '\n';
}
recovery.close();
return 0;
}
Append-Mode Sequential Injection
When updating an existing dataset, std::ios::app positions the write cursor at the physical end of the file. This prevents overwriting prior entries. The routine below iteratively injects incremental counters into an archive file.
#include <iostream>
#include <fstream>
bool append_sequence(const char* filepath, int start_val, int end_val) {
std::ofstream stream(filepath, std::ios::app);
if (!stream) {
return false;
}
for (int counter = start_val; counter <= end_val; ++counter) {
stream << " [val:" << counter << "]";
}
stream << '\n';
return true;
}
int main() {
if (append_sequence("archive_log.dat", 1, 10)) {
std::cout << "Batch insertion successful." << std::endl;
} else {
std::cerr << "Insertion aborted due to I/O constraints." << std::endl;
}
return 0;
}
Operational Best Practices
Buffer overflow prevention should always precede array-based writes. Using std::string or std::vector<char> eliminates manual size calculations. Stream state flags like .eof(), .bad(), and .fail() provide diagnostic feedback during prolonged operaitons. Explicit .close() calls trigger internal synchronization and release OS-level file descriptors, though destructors typically automate this when scopes exit. Binary formats omit delimiter injection and require consistent byte-order awareness across platforms, whereas text streams automatically handle newline translation depending on the host environment.