4

Consider i have following file ("testt.txt")

abc
123
def
456
ghi
789
jkl
114

Now if i wanted to update the figure next to name ghi (i.e. 789), how would i do it?

The following code helps me reach there quickly no doubt, but how to update it quickly?

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

using namespace std;

int main() 
{
    int counter = 0;
    string my_string;
    int change = 000;
    ifstream file ( "testt.txt" );

    while(!file.eof())
    {
        counter = counter + 1;
        getline(file, my_string, '\n');
        if (my_string == "ghi") 
        {
            ofstream ofile ( "testt.txt" );
            for (int i = 0; i < counter + 1; i++)
            {
                //reached line required i.e. 789
                //how to process here?
            }
            ofile.close();
            break;
        }
    }
    cout << counter << endl;
    file.close();
    return 0;
}

Clearly the counter here is 5 corresponding to "ghi", so counter + 1 would point to value 789. How to change it to 000?

------------SOLVED-----------FINAL CODE------

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

using namespace std;

int main() 
{
string x;
ifstream file ( "testt.txt" );
ofstream ofile ( "test2.txt" );
while (!file.eof())
{
    getline(file,x);
    if (x == "789")
    {
        ofile << "000" << endl;
    }
    else
        ofile << x << endl;
}
file.close();
ofile.close();
remove("testt.txt");
return 0;
}

Output ("test2.txt")

abc
123
def
456
ghi
000
jkl
114
bikrathor
  • 96
  • 1
  • 1
  • 7
  • [`while(!file.eof())`](http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) – πάντα ῥεῖ Jun 14 '15 at 07:57
  • Consider using a database, because those operations tend to be complicated using simple file access. Anyhow, the way you approach the problem, it boils down to "read data", "modify data", "write data", which is cumbersome but possible. At which step exactly do you have problems? – Ulrich Eckhardt Jun 14 '15 at 07:57
  • you can see, it is written in for loop,, and any other method that can be used without database?? i mean to write updated data to a new file and delete old one.. – bikrathor Jun 14 '15 at 08:01
  • @bikrathor It is possible if you have all certain fixed positions of data. Look into the [`std::basic_ostream::seekp()`](http://en.cppreference.com/w/cpp/io/basic_ostream/seekp) method. – πάντα ῥεῖ Jun 14 '15 at 08:09

2 Answers2

2

If you open a file with ifstream for reading, and then with ofstream for writing, the ofstream will either not work or overwrite the file - I am not sure which option is right, but neither is what you want.

So use std::fstream to open a file for reading and writing:

fstream file ( "testt.txt" );

After arriving to the proper place, use the seekp method to enable writing to the stream after reading from it (it often works without seekp, but when it fails, the bug is very difficult to find), as required by the Standard:

if (my_string == "ghi") 
{
    file.seekp(file.tellg());
    ...
    break;
}

When modifying files, you have to replace the existing bytes with the new ones. It's important to write exactly 3 bytes, so the value 789 is overwritten properly. So you may want to check the range:

if (change < 0 || change > 999)
    abort(); // or recover from the error gracefully

And set the width of the output field before writing it:

file << setw(3) << change;

If your code switches from writing back to reading, use file.seekg(file.tellp()) to ensure it works properly.

πάντα ῥεῖ
  • 83,259
  • 13
  • 96
  • 175
anatolyg
  • 23,079
  • 7
  • 51
  • 113
0

Doing that is not generally easy, because file systems don't store files line-wise, but instead as sequence of bytes. So if you replace a line with let's say 4 characters in it by a line with 5 characters, you will overwrite something in your next line. You'd have to read the file into memory, and then re-write everything from your changed line on.

That's a horrible approach, because it is incredibly slow, and if you can avoid it by not using a text file to store this kind of information, you should do that. I generally recommend using something like sqlite, for which libraries for all relevant languages exist, if you need to store data in things that feel like tables; for other kind of data, there's other approaches than relational databases, but that depends on what you want to actually store.

Marcus Müller
  • 27,924
  • 4
  • 40
  • 79
  • _"There's no way to do that ..."_ That's simply not true. – πάντα ῥεῖ Jun 14 '15 at 08:16
  • @πάνταῥεῖ: Yeah, and I even go as far as describing how it's possible... Well, I'm off, editing my answer. – Marcus Müller Jun 14 '15 at 08:18
  • Not really, in terms of answering the OP's original question. – πάντα ῥεῖ Jun 14 '15 at 08:20
  • @πάνταῥεῖ: That depends on what you view as the "original question", and even more on whether you view "original question" as a relevant concept -- you know, everything flows :-D no, in fact, OP asked how to change that line, and my answer was "write the new line and all lines following", and I honestly believe that answers his question. The "no way to do that" start of my answer came from OP asking "is there a way to do that quickly", and generally, there's not, if his file goes on for Gigabytes. – Marcus Müller Jun 14 '15 at 08:24
  • Take OP's seriously in what they want to achieve in code, and show them how to. If you think it's an XY problem asked for, then extend this as a comment or additional notes in your answer. – πάντα ῥεῖ Jun 14 '15 at 08:27
  • @πάνταῥεῖ: Definitely taking OP seriously. The question was *The following code help me reach there quickly no doubt, but how to update it quickly??*, and my answer is *how you can update it and why it's not generally possible to do it fast*, so I think it doesn't need further commentation; I see you disagree with me here. – Marcus Müller Jun 14 '15 at 08:34
  • @marcus , could you please help me onto how to start editing from that line and write onto a new file?? – bikrathor Jun 14 '15 at 08:36
  • @bikrathor: Use your existing code to write every line you read (up to, and including "ghi") to your `ofile`, then write `"000"`,and skip the next line on the input file, and then continue to write everything that is in the input file to the output file. – Marcus Müller Jun 14 '15 at 08:41
  • o yeah great @marcus, and any way there to delete the old one i.e testt.txt?? – bikrathor Jun 14 '15 at 08:48
  • @bikrathor: try not using the same in and output file, for that matter; you'll notice that the "old" line never gets written to the output file. As I explained in my answer, you will have to read in everything that comes after "ghi" into memory, and then put it back into your combined in- and output file if you need to change the length of your line. – Marcus Müller Jun 14 '15 at 08:53
  • yeah i wrote the following code, and it created a new file my work done but how to delete the old one i.e. testt.txt? – bikrathor Jun 14 '15 at 08:58
  • string x; ifstream file ( "testt.txt" ); ofstream ofile ( "test2.txt" ); while (!file.eof()) { getline(file,x); if (x == "456") { ofile << "000" << endl; } else ofile << x << endl; } file.close(); ofile.close(); – bikrathor Jun 14 '15 at 08:58
  • yeah it does but now i want to but now i want to delete the old one dude – bikrathor Jun 14 '15 at 09:00
  • @bikrathor: Ah you mean "delete the file", and not "delete the line", here. Well: `#include ` and then `std::remove("filename")`, see `man remove` or http://www.cplusplus.com/reference/cstdio/remove/ – Marcus Müller Jun 14 '15 at 09:04
  • @bikrathor: happy to hear it worked out. I think my answer would profit from you editing it, adding your (complete) code, so that people can later find it :) – Marcus Müller Jun 14 '15 at 09:11