You can force the stream to empty its buffer into an output file, or to refill its buffer from an input file. This is done through the stream buffer's public member function pubsync(). Typically, you call pubsync() indirectly through functions of the stream layer. Input streams and output streams have different member functions that implicitly call pubsync().
Output streams have a flush() function that writes the buffer content to the file. In case of failure, badbit is set or an exception thrown, depending on the exception mask.
std::ofstream ofstr("/tmp/fil"); ofstr << "Hello "; //1 ofstr << "World!\n"; ofstr.flush(); //2
//1 | The attempt to extract anything from the file /tmp/fil after this insertion will probably fail, because the string "Hello" is buffered and not yet written to the external file. |
//2 | After the call to flush(), however, the file contains "Hello World!\n". (Incidentally, the call to ostr.flush() can be replaced by the std::flush manipulator; that is, ostr << std::flush;) |
Keep in mind that flushing is a time-consuming operation. The member function flush() not only writes the buffer content to the file; it may also reread the buffer in order to maintain the current file position. For the sake of performance, you should avoid inadvertent flushing, as when the std::endl manipulator calls flush() on inserting the end-of-line character. (See Section 28.3.2.)
Input streams define the sync() member function. It forces the stream to access the external device and refill its buffer, beginning with the current file position. In the case of input streams, the behavior of sync() is implementation-defined, that is, not standardized. The traditional iostreams had a sync() function that did the expected synchronization, that is, refilling the buffer beginning with the current file position.
The example below demonstrates the principle theoretically. In real life, however, the two streams might belong to two separate processes. (For example, if two processes communcate through a shared file.) It should be noted that the exact behavior of the example below depends on the size of the internal buffers and other inherently implementation-specific parameters.
std::ofstream ofstr("/tmp/fil"); std::ifstream ifstr("/tmp/fil"); std::string s; ofstr << "Hello "; std::ofstream::pos_type p = ofstr.tellp(); ofstr << "World!\n" << std::flush; ifstr >> s; //1 ofstr.seekp(p); ofstr << "Peter!" << std::flush; //2 ifstr >> s; //3 ofstr << " Happy Birthday!\n" << std::flush; //4 ifstr >> s; //5 ifstr.sync(); //6 ifstr >> s;
//1 | Here the input stream extracts the first substring, "Hello", from the shared file. In doing so, the input stream fills its buffer. It reads as many characters from the external file as needed to fill the internal buffer. For this reason, the number of characters to be extracted from the file is implementation-specific; it depends on the size of the internal stream buffer. We will assume for the remainder of this discussion that the entire external sequence has been read into the internal buffer. |
//2 | The output stream overwrites part of the file content. Now the file content and the content of the input stream's buffer are inconsistent. The file contains "Hello Peter!"; the contents of the input stream's buffer are unchanged and still contain "Hello World!". |
//3 | This extraction takes the string "World!" from the buffer instead of yielding "Peter!", which is the current file content. Since the file ends with a new line, the extractor terminates as soon as it encounters '\n' without setting eofbit. Had the the file not been new line terminated the extractor would have set eofbit. |
//4 | More characters are appended to the internal buffer and subsequently flushed to the the external file. The file now contains "Hello Peter! Happy Birthday!". The input stream's buffer has not changed. |
//5 | This extraction yields "Happy". The stream extractor first extracts the new line character that terminated input in 2. Since the default behavior is to skip all whitespace, the function proceeds extracting subsequent characters from the buffer. However, since the new line was the last character available in the internal buffer, the latter underflows and is refilled from the external sequence. The string "Happy Birthday!\n" is read in from the file and the first space-delimited substring is stored in s. |
//6 | A call to sync() eventually forces the input stream to refill the buffer from the external device. The buffer tries to maintain the current position within the external device. After the synchronization, the input stream's buffer contains at the very least the initial substring " Birthday!\n", and the next extraction yields "Birthday!".
As the standard specifies the behavior of sync() as implementation-defined, you can alternatively try repositioning the input stream to the current position instead; for example, istr.seekg(std::ios_base::cur);. |
NOTE -- If you must synchronize several streams that share a file, it is advisable to call the sync() function after each output operation and before each input operation.