Intermediate 13 min

File Stream Manipulation

Master advanced file stream operations including seeking, positioning, and state management

Learn advanced file stream techniques including random access, position manipulation, and stream state management.

A Simple Example

#include <iostream>
#include <fstream>
#include <string>

void demonstratePositioning() {
    std::ofstream outFile{"demo.txt"};
    outFile << "Hello, World!\n";
    outFile << "Second line\n";
    outFile << "Third line\n";
    outFile.close();

    std::ifstream inFile{"demo.txt"};

    // Get current position
    std::cout << "Initial position: " << inFile.tellg() << "\n";

    // Read first line
    std::string line;
    std::getline(inFile, line);
    std::cout << "Read: " << line << "\n";
    std::cout << "Position after read: " << inFile.tellg() << "\n";

    // Seek to beginning
    inFile.seekg(0, std::ios::beg);
    std::cout << "After seekg(0): " << inFile.tellg() << "\n";

    // Seek to end
    inFile.seekg(0, std::ios::end);
    std::cout << "File size: " << inFile.tellg() << " bytes\n";

    // Seek to beginning and read again
    inFile.seekg(0);
    std::getline(inFile, line);
    std::cout << "First line again: " << line << "\n";
}

int main() {
    demonstratePositioning();
    return 0;
}

Breaking It Down

tellg() and tellp() - Get Position

  • tellg(): Returns current get (read) position in input stream
  • tellp(): Returns current put (write) position in output stream
  • Returns std::streampos (essentially a byte offset)
  • Remember: Position starts at 0 (beginning of file)

seekg() and seekp() - Set Position

  • seekg(pos): Seek to absolute position in input stream
  • seekp(pos): Seek to absolute position in output stream
  • seekg(offset, origin): Seek relative to origin (beg, cur, end)
  • Remember: seekg for reading, seekp for writing

Stream Origins for Relative Seeking

  • std::ios::beg: Beginning of stream (offset 0)
  • std::ios::cur: Current position
  • std::ios::end: End of stream
  • Example: seekg(-10, std::ios::end) moves 10 bytes before end

Stream State Management

  • After EOF, you must clear() before seeking
  • Check stream state with good(), fail(), eof()
  • clear() resets error flags but doesn't change position
  • Remember: Always verify stream state after operations

Why This Matters

  • Sometimes you need more than sequential file reading. Database-like applications require jumping to specific records, log parsers need to read backwards, and file editors must modify data at arbitrary positions.
  • Understanding stream manipulation and state management is essential for building robust file-handling code.
  • These techniques enable efficient random access to large files without loading everything into memory.

Critical Insight

Seeking makes files act like random-access arrays. Just like you can access array[10] directly, you can seek to byte 10 * sizeof(Record) and read that record instantly. This is how databases achieve fast lookups - they calculate the exact byte position and seek there directly, no scanning required.

Combine this with indexing, and you've built the foundation of a database engine! Instead of reading the entire file line by line, seek directly to the data you need.

Best Practices

Always check stream state: Verify the stream is good() after seek operations to ensure they succeeded.

Clear error flags after EOF: Call clear() to reset EOF and error flags before seeking after reaching end of file.

Use tellg() to save positions: Store positions with tellg() to return to specific locations later.

Prefer text mode for text files: Binary mode positions can differ from text mode on some platforms due to newline conversion.

Common Mistakes

Not checking stream state after seeking: Always verify the stream is still good() after seek operations.

Forgetting to clear() after EOF: Once a stream hits EOF, you must call clear() before seeking and reading again.

Mixing text and binary positions: In text mode on some platforms, positions aren't simple byte counts due to newline conversion.

Seeking in write mode without flushing: Seek operations may not work correctly if the buffer hasn't been flushed.

Debug Challenge

This code tries to read from the beginning after reaching EOF. Click the highlighted line to fix it:

1 #include <fstream>
2 #include <string>
3
4 int main() {
5 std::ifstream file{"data.txt"};
6 std::string line;
7 while (std::getline(file, line)) { } // Read to EOF
8 file.seekg(0); // Try to go back to start
9 std::getline(file, line); // Won't work!
10 return 0;
11 }

Quick Quiz

  1. What does tellg() return?
The current read position in the stream
The number of bytes read so far
The total size of the file
  1. What happens if you seekg() beyond the end of a file?
The file is extended
The stream enters an error state
It automatically seeks to the end
  1. After hitting EOF, what must you do before seeking?
Nothing, just seek
Close and reopen the file
Call clear() to reset state flags

Practice Playground

Time to try out what you just learned! Play with the example code below, experiment by making changes and running the code to deepen your understanding.

Lesson Progress

  • Fix This Code
  • Quick Quiz
  • Practice Playground - run once