Suppose my file a.txt has "ABC" written in it. Now I want to write a small b before capital B in the file. How will I do it?

I've tried to do it but i'm having problems.
1. When opened in app mode seekp doesn't work.
2. When opened normally previous written data is erased.

Dani AI

Generated

Insertion in the middle of a file requires shifting the bytes that follow — you cannot simply "insert" a byte without moving the rest. Two common pitfalls you ran into are: opening with append mode (std::ios::app) forces every write to the end, so calls to seekp() will not place subsequent writes where you expect; and opening with a plain std::ofstream (default) truncates the file, which is why earlier data was lost.

As and suggested, the simplest approaches are (a) read the file into memory, modify, then overwrite, or (b) copy to a temp file while inserting. If you want to avoid a full in-memory copy and also avoid a second file, you can shift the trailing bytes forward in blocks using a single read/write stream. Below is an example that finds the first 'B', extends the file by one byte, then moves blocks from the end backward and finally writes the inserted 'b'. It uses a plain char buffer (no STL container) so it is friendly if you have not covered std::vector yet.

#include <fstream>

bool insert_before_first_B(const char* filename, char to_insert='b') {
    std::fstream f(filename, std::ios::in | std::ios::out | std::ios::binary);
    if (!f) return false;

    // find first 'B'
    f.seekg(0, std::ios::beg);
    char ch; std::streamoff pos = -1;
    for (std::streamoff i = 0; f.get(ch); ++i)
        if (ch == 'B') { pos = i; break; }
    if (pos < 0) return true; // nothing to insert before

    f.seekg(0, std::ios::end);
    std::streamoff orig_size = f.tellg();

    // extend file by one byte
    f.seekp(0, std::ios::end);
    f.put('\0');
    f.flush();
    f.clear();

    const std::size_t BUF = 4096;
    char* buf = new char[BUF];

    std::streamoff read_from = orig_size - 1;
    while (read_from >= pos) {
        std::streamsize chunk = (read_from - pos + 1) < BUF ? (read_from - pos + 1) : BUF;
        std::streamoff start = read_from - chunk + 1;
        f.seekg(start);
        f.read(buf, chunk);
        std::streamsize got = f.gcount();
        f.clear();
        f.seekp(start + 1);
        f.write(buf, got);
        read_from = start - 1;
    }
    delete[] buf;

    f.seekp(pos);
    f.put(to_insert);
    f.close();
    return true;
}

Notes and troubleshooting:

  • Open in binary mode when doing byte-level edits (CRLF translations on Windows change byte counts).
  • Don’t use std::ios::trunc or plain std::ofstream if you need to preserve contents.
  • If the file is huge or you need many edits, prefer the temp-file approach or a memory-mapped API for performance; for rich text editing algorithms, see buffer-gap techniques mentioned by .

Recommended Answers

All 6 Replies

If I was doing this I would read each line of the file into a string array. After that I would go through each string in the array and insert a b in front of every B. Then I would just overwrite the contents of the file with the modified array.

Open your file(a.txt) and a temp file. Read the a.txt file writing the results to the temp file. If one of the characters to be written is B then write b first.

Finally, delete a.txt and rename temp to a.txt.

HOw will you overwrite the file with modified string? Same problem will occur which I've mentioned.

Unfortunately, there is no real answer other than to read the file contents after the point of insertion, and re-write them with an offset equal to the size of the text you are inserting (one byte, in this case). Given the size of the file, it may be easier to simply read the whole text beyond the insertion point into memory, do the insertion, and write it all back.

Can you tell us something of the actual goal of your program? This question has the feel of a simplified example. For more elaborate editing, you might want to read up about the 'buffer gap' technique, which is described in detail in the online textbook The Craft of Text Editing.

As for why seekp() "isn't working", in append mode, just how were you trying to use it? Keep in mind that seekp() sets the position for writing, but to set the position for reading, you need to use seekg().

This is a shell for what I would do.

std::string filename;
// get the filename and put it in the string

std::ifstream fin(filename.c_str());
std::vector<std::string> file;
std::string line;

// read in file
while (std::getline(fin, line))
    file.push_back(line)

fin.close();
for(int i = 0; i < file.size(); i++)
{
    // code to go through the string and add 'b' before 'B' here
    // using the string methods find() and insert() will help here
}

// write the vector to the file replacing the old version of the file
std::ofstream fout(filename.c_str())
for (int i = 0; i < file.size(); i++)
    fout << file[i];

fout.close();

Thanks NathanOliver, we haven't read about vectors yet.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.