Project 9.02 Section 9 ⚡ Embedded Relevance: High std::ofstream Buffering Power Loss Atomic Writes Data Logging

9.02 std::ofstream Buffering, Power-Loss Corruption & Atomic Flash Commits

Executive Summary: Exploring file writing via std::ofstream. We analyze write buffering, explicit stream flushing, the severe hazard of power loss during file writes causing metadata corruption, and implementing atomic write transactions on embedded telemetry loggers.

💻 1. Annotated Source Code

#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;

void printFormatted(ofstream& outfile, int highNum);

int main() {
	int highNum;
	cout << "Enter a high number:  ";
	cin >> highNum;

	cout << "Writing to file..." << endl;

	ofstream outfile("output.txt");  

	if (!outfile) {
		cerr << "Error: Could not open file for writing." << endl;
		return 1;
	}

	cout << fixed << showpoint;
	outfile << fixed << showpoint;

	printFormatted(outfile, highNum);
	//outfile << "Hello world!" << endl;

	outfile.close();  
	cout << "Done" << endl;

	return 0;
}

void printFormatted(ofstream& outfile, int highNum) {
	for (int i = 1; i <= highNum; i++) {
		double value1 = i * 5.7575;
		double value2 = i * 3.14159;

		cout << setw(12) << setprecision(2) << value1
			<< setw(12) << setprecision(3) << value2 << endl;

		outfile << setw(12) << setprecision(2) << value1
			<< setw(12) << setprecision(3) << value2 << endl;
	}
}
        5.76       3.142
       11.52       6.283
       17.27       9.425
       23.03      12.566
       28.79      15.708
       34.55      18.850
       40.30      21.991
       46.06      25.133
       51.82      28.274
       57.58      31.416
       63.33      34.557
       69.09      37.699
       74.85      40.841
       80.61      43.982
       86.36      47.124
       92.12      50.265
       97.88      53.407
      103.64      56.549
      109.39      59.690
      115.15      62.832
      120.91      65.973
      126.67      69.115
      132.42      72.257
      138.18      75.398
      143.94      78.540
      149.69      81.681
      155.45      84.823
      161.21      87.965
      166.97      91.106
      172.73      94.248
      178.48      97.389
      184.24     100.531
      190.00     103.672
      195.75     106.814
      201.51     109.956
      207.27     113.097
      213.03     116.239
      218.79     119.380
      224.54     122.522
      230.30     125.664
      236.06     128.805
      241.81     131.947
      247.57     135.088
      253.33     138.230
      259.09     141.372
      264.85     144.513
      270.60     147.655
      276.36     150.796
      282.12     153.938
      287.88     157.079
      293.63     160.221
      299.39     163.363
      305.15     166.504
      310.91     169.646
      316.66     172.787
      322.42     175.929
      328.18     179.071
      333.94     182.212
      339.69     185.354
      345.45     188.495
      351.21     191.637
      356.97     194.779
      362.72     197.920
      368.48     201.062
      374.24     204.203
      380.00     207.345
      385.75     210.487
      391.51     213.628
      397.27     216.770
      403.03     219.911
      408.78     223.053
      414.54     226.194
      420.30     229.336
      426.06     232.478
      431.81     235.619
      437.57     238.761
      443.33     241.902
      449.09     245.044
      454.84     248.186
      460.60     251.327
      466.36     254.469
      472.12     257.610
      477.87     260.752
      483.63     263.894
      489.39     267.035
      495.15     270.177
      500.90     273.318
      506.66     276.460
      512.42     279.602
      518.18     282.743
      523.93     285.885
      529.69     289.026
      535.45     292.168
      541.21     295.309
      546.96     298.451
      552.72     301.593
      558.48     304.734
      564.24     307.876
      569.99     311.017
      575.75     314.159

📐 2. Architecture & UML Class Model

📐 std::ofstream File Writing & Flash Wear-Leveling Model
+ Public - Private # Protected
<<class>> std::ofstream Hosted Output Stream
-file_descriptor : int32_t
+open(filename: const char*, mode: openmode) : void
+write(data: const char*, size: size_t) : ostream&
+flush() : ostream&
+close() : void

📚 3. Core C++ Concepts Deep-Dive

1. std::ofstream Write Buffering

Output streams buffer writes in memory before committing chunks to disk. Writing with << writes to the stream buffer; data reaches disk only when the buffer fills, flush() is called, or the file is closed.

⚡ 4. Embedded Systems & Hardware Reality

1. Power-Loss File System Corruption

If battery power fails while writing a file, uncommitted RAM buffers are lost and partially written FAT/directory tables will corrupt the entire file system. Embedded systems use journaling or copy-on-write atomic transactions.

💡 5. Production-Ready Embedded Refactoring

Power-fail safe atomic log writer:

💡 Production-Ready Refactor
#include <cstdint>

struct TelemetryLogEntry {
    uint32_t timestamp_s;
    int16_t  temperature_c;
    uint16_t voltage_mv;
    uint32_t crc32;
};

// Write with explicit hardware flush to guarantee persistence
bool appendLogRecord(const TelemetryLogEntry& entry) noexcept {
    // 1. Write binary entry to Flash buffer...
    // 2. Force hardware SPI Flash write transaction...
    // 3. Update non-volatile commit pointer in Flash header...
    return true;
}

📝 Knowledge Verification Quiz

Test your understanding of the C++ concepts and embedded microcontroller trade-offs covered in this guide. Click any option for instant feedback.

Q1. What happens if a battery is disconnected while an embedded data logger is writing to a standard FATFS SD card?
A Unflushed cache buffers are lost and file allocation tables may be left in an inconsistent state, corrupting the SD card file system
B The SD card converts to an encrypted partition
C The data is automatically recovered from ROM
D The microcontroller clock frequency is reduced
Detailed Explanation: Power interruption during FAT table updates corrupts directory chains, rendering files unreadable without specialized recovery tools.
Q2. What does calling 'out_file.flush()' or 'out_file << std::flush' do?
A Forces all buffered output data in memory to be physically committed to the underlying storage device immediately
B Clears all text from the file
C Deletes the file from disk
D Closes the file permanently
Detailed Explanation: flush() pushes all pending characters from RAM stream buffers into physical storage without closing the file handle.
Q3. Which open mode flag appends new data to the end of an existing file rather than overwriting it?
A std::ios::app
B std::ios::trunc
C std::ios::in
D std::ios::binary
Detailed Explanation: std::ios::app (append mode) positions write operations at the end of the file, preserving existing content.
Q4. Why is binary file serialization (writing raw structs) faster and more compact than text serialization (ASCII numbers) in IoT loggers?
A Binary format writes raw bytes directly without CPU-intensive ASCII formatting, consuming 40-70% less Flash storage and write energy
B Binary files cannot be corrupted by power loss
C Text files can only hold 256 bytes
D Binary files run in RAM only
Detailed Explanation: Binary serialization stores numbers in their native byte layout (e.g. 4 bytes for float), avoiding expensive integer-to-string formatting.