I'm currently writing a program and I want it to read in data from a source and if needed change some or all of it and re-write it to the same source file.
I have:
where all the variables are ints in a struct called date.
ifstream ifs("data.txt");
ifs>>date.hours;
ifs>>date.minutes;
ifs>>date.month;
ifs>>date.day;
ifs>>date.year;

and to output I have:
ofstream ofs("data.txt");
ofs<<date.hours;
ofs<<date.minutes;
ofs<<date.month;
ofs<<date.day;
ofs<<date.year;

Right now I read all of the data into the strut and do what ever operations I need and then read it all back. The problem is in larger text files I still need to read it all into my program, and then read it all back out. Is there a way to read in only one entry say minutes, and change it and then write it back as the new value WITHOUT having to read and write the rest of the text file entries. So I can just change the one entry?

>So I can just change the one entry?
Yes, but only if the entry or record is a fixed length. Otherwise you risk overwriting the next entry. Can you describe the format of your file? That's a huge factor in how you read from and write to it.

The format looks something like this:
21 10 3 13 2005
for each entry which corresponds to the form: hour-minute-month-day-year
The first number in the file is the number of entries in the file. So a file with 3 sets of date looks like this:

3
21 10 3 13 2005
12 8 4 9 2004
3 6 10 31 2004

If there is an easier way to make this file i'm open to suggestions.

Consider the following pseudocode for modifying a record:

while ( !in.eof() ) {
  pos = in.tellg();
  rec = read_rec ( in );
  if ( rec == search_rec ) {
    modify_field ( rec, new_entry );
    in.seekg ( pos );
    write_rec ( rec );
  }
}

A good C++ reference should should give you the details. :)

Ok thanks,
correct me if I'm wrong though but that code only works as long as you know precisely how many char's it is until the entry u want to write? Or is it possible to allow it to read each entry instead of each Char. Or am I totally off base here and need to find a new C++ reference.

>only works as long as you know precisely how many char's it is until the entry u want to write?
Nope, with your format you only need to know how many fields are in the record before the one you want to modify. Since each record is on a separate line, in.tellg() saves the location at the beginning of each record so that you can return to the beginning of the line and rewrite the record. Here's a sample execution with the file you gave:

21 10 3 13 2005
12 8 4 9 2004
3 6 10 31 2004

Say you want to change 12 8 4 9 2004 to 12 8 4 11 2004. in.tellg() saves the position just before 21. You read the record, then test it to see if it's the one you want. The test fails, so the loop continues to the next iteration. in.tellg() saves the position just before 12 and the record is read. The test succeeds because this is the record you want to change, so modify_record is called to change 9 to 11. How it does so is irrelevant to the loop. With the modified record in hand, in.seekp ( pos ) resets the file pointer to the beginning of the line so that the new record can be rewritten over the old record.

21 10 3 13 2005
12 8 4 9 2004
3 6 10 31 2004

Say you want to change 12 8 4 9 2004 to 12 8 4 11 2004

Wouldn't the resulting string being 1 byte longer overwrite the "3" in the next position (record)? Often when confronted with this type of data I prefer to pad values that will be less than 10 with zeros.

ie
21 10 03 13 2005
12 08 04 09 2004
03 06 10 31 2004

That makes each record a fixed length and maybe a little easier to code.

Ignore everything I said, I've been working with record-oriented files too much. Let's try again, this time when I'm actually thinking about the problem at hand instead of making it up as I go along.

>Is there a way to read in only one entry say minutes, and change it and
>then write it back as the new value WITHOUT having to read and write the
>rest of the text file entries.
With byte-oriented files, no, not really. There isn't a convenient and efficient way to shift bytes, so you're looking at the same issue as if you wanted to insert new data into an array. Technically, you only need to rewrite everything after and including the modified record, and a rewrite of the latter part of the file is only necessary if the new record differs in byte size from the old record. Even then, you can pad with empty space if the new record is smaller.

It would probably be better in your case to work with each line on a case by case basis, using a temporary file as your output. That way you only have to keep one record in fast memory at a time, and the temporary file can simply be renamed to replace the old file. No more copying is necessary at that point, but you still have to read and write the entire contents of the file once.

This article has been dead for over six months. Start a new discussion instead.