开发者

Partial write to a file - C++

I'm working with VS2010, in C++.

I have a class called Ro开发者_JAVA百科om. Room has an x and a y property, and then a bunch of other properties.

I have a file called Rooms.txt, which contains a bunch of properties for a 'Room' object. It uses a custom syntax, so that one entry might look like this:

$x$y$name$size$type$state$EOL@$

So I've got the following working fine: the player inputs an X and Y coordinate, and the values for the corresponding entry in the text file are given to a Room object.

What I want to then do is allow the player to change some of these variables and write them back to the file, but I can't quite figure out how. This is my best effort so far:

    ifstream inRoom;
ofstream outRoom;
string path = saveRoot;
path.append(ModLoad); // the last two lines get the path for the file to be read/written

inRoom.open(path);
//outRoom.open(path);
string temp;
string temp2;
if(inRoom.bad()){
    cout << "ERROR: Bad save!";
}
while(inRoom.good()){
    temp2 = temp;
    getline(inRoom,temp,'$');
    cout << temp <<inRoom.tellg();
    if ((atoi(temp2.c_str())==myPlayer.X)&&(atoi(temp.c_str())==myPlayer.Y)){
        int seek = inRoom.tellg();
        inRoom.close();
        cout << "Opening " << path << "for writing \n";
        outRoom.open(path);
        outRoom.seekp(seek);
        outRoom.write("HELLO!", 6);
        outRoom.close();
    }
}
inRoom.close();

Also, I need to overwrite the values, not insert new data. Any thoughts?


You've chosen the wrong format. For overwriting to work you need a fixed width format. So every room takes up the same number of bytes in your file, no matter what. That way when you overwrite a room you can just put the new room over the top of the old room without worrying about whether you are going to have to insert a few bytes or delete a few bytes from the file as a whole.

Also it would really make you life easier if you had a formula to tell the position of a room in your file directly from the x and y coordinates. Instead of having to loop though the file looking for the right room, you could seek to the right place immediately.


Rewriting only some data in a file requires two things:

  • You have to know the position in the file where to start writing. Then you can go to that position using seekp() as you did.
  • More tricky: The data written have to be exact the same number of bytes. Otherwise you will overwrite following data or leave some old bytes messing the structure of your file.

To open the file for rewriting parts use

file.open(filename, ios::binary|ios::in|ios::out|ios::ate);
file.seekg(0);
// or go to the position to read your data directly
// store that position using tellg()
// read data
// restore position using tellp()
// write data (in exact same length)

As I remember the trick here is to open the file at its end ios::ate. Otherwise you may (partially) loose the content of the file.


Remember, you are using C++, so you have to think objects. What I'd do is:

  • Add serialization to your Room class by overloading >> and << operators
  • Read the list of entries into the memory (using, for example, std::vector) at the start of the execution
  • When user enters X and Y, lookup corresponging entry in the list of entries stored in the memory and display it
  • If user modifies something, replace the existing entry in the memory with a new one
  • Write the whole list of entries back to the file completely replacing its content

Here's a quick and dirty code draft just to show the idea:

#include <vector>
#include <iostream>
#include <fstream>
#include <iterator>

class Room
{
    public:
        int x;
        int y;
        std::string a;
        std::string b;

    private:
        friend std::ostream& operator <<(std::ostream& os, const Room& r);
        friend std::istream& operator >>(std::istream& is, Room& r);

};

std::ostream& operator <<(std::ostream &os, const Room& r)
{
    return os << r.x << r.y << r.a << r.b;
}

std::istream& operator >>(std::istream& is, Room& r)
{
    return is >> r.x >> r.y >> r.a >> r.b;
}


int main()
{
    std::vector<Room> roomList;

    // read the list
    ifstream in("out.txt");
    istream_iterator<Room> ii(in), iieof;
    copy(ii, iieof, back_inserter(roomList));
    in.close();

    // do something with your data
    // ...

    // save the modified list back
    ofstream out("out.txt");
    ostream_iterator<Room> oi(out, "\n");
    copy(roomList.begin(), roomList.end(), oi);
    out.close();

    return 0;    
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜