Answer
Reopening a FileStorage object with the APPEND flag after a transient I/O failure positions the write pointer at the end of the file, provided the file itself is intact and the underlying open() call succeeds.
Confirmed facts (based on OpenCV implementation)
- In
APPEND mode OpenCV opens the file with std::ios::app; each write operation seeks to the current end‑of‑file before serializing a node.
- If a write fails because of a transient I/O error, the stream’s
failbit is set. Subsequent << operations are ignored until the error state is cleared.
- The
FileStorage object does not automatically clear the error state; you must check isOpened() or the stream’s error flags, release the storage, and reopen the same file with the APPEND flag to reset the stream.
- After a successful reopen, the file pointer is again at the end of the file, so a retry will append new data without duplicating existing content, assuming the file system call succeeds.
Likely explanation for the observed behavior
When the failure occurs mid‑node, the partially written bytes remain in the file, but the stream’s error state prevents further writes. Reopening with APPEND does not truncate or repair the file; it simply positions the pointer at the current end‑of‑file (which includes the partial node). Therefore, the retry will add new data after the incomplete node, leaving the file with a malformed segment unless the application detects and discards the partial node.
Steps to implement a safe retry
- Attempt the write operation inside a try/catch or check the return value of
operator<< (or write()) and test storage.fail().
- If a failure is detected, call
storage.release() to close the stream and clear the internal FileStorage state.
- Reopen the same file with
FileStorage storage(filename, FileStorage::APPEND).
- Optionally verify that
storage.isOpened() is true and !storage.fail() before proceeding.
- Repeat the write operation. If the same logical data is written again, you will get duplicate nodes unless you track what has already been persisted (e.g., by storing a version or UUID and skipping the write on retry).
- If the reopen fails repeatedly, treat the error as permanent and abort or switch to an alternative storage location.
Missing diagnostic detail that would change the recommendation
Can you confirm whether the file contains a partially written node after the failure? If a partial node is present, the application must either truncate the file to the last good boundary or detect and skip the malformed content on retry; otherwise simply reopening in APPEND mode will leave corrupted data in the file.
Verification (optional)
// Simulate transient failure
cv::FileStorage fs("test.yml", cv::FileStorage::WRITE | cv::FileStorage::APPEND);
fs << "mat" << cv::Mat::eye(3,3,CV_64F);
// Inject error: close underlying file descriptor or simulate disk full
// ...
if (fs.fail()) {
fs.release();
fs.open("test.yml", cv::FileStorage::APPEND); // retry
fs << "mat" << cv::Mat::eye(3,3,CV_64F);
}
fs.release();
// Read back and check for duplicates or corruption
cv::FileStorage fr("test.yml", cv::FileStorage::READ);
// ...