I'm trying to get a binay file open to save the high scores of the game I'm writing. Heres how I'm doing it. (posted in order of calling)
[global]
fstream sav;
[main()]
sav.open("hssav.sav", ios::binary|ios::in|ios::out);
[game() function called by main()]
textprintf(buffer, font, SCREENW / 2, 30, BLUE, "Opened? %d", ((int)sav.is_open()));
//prints the integer result of (int)sav.is_open()
[exit(function called by main)]
sav.close();
(int)sav.is_open is returning 0, I think that means that the object couldn't open the file. Am I right? Assuming I am, why would that be? Doesn't open(...) create the file if it doesn't exist. If not, how do I go about creating the file? That is is important because I want hssav.sav to be created at runtime if it doesn't already exist.
I haven't tried reading or writing yet, I figure there isn't a point in trying to read or write if there is no file.
Have you tried passing the full path instead of just the file name? Like C:/test/hssav.sav (note that you use /, not the evil \). Does it work with the full path? Try not to use spaces in the path.
Maybe you don't have permissions to write to the working directory?
Maybe your OS cant handle having input and output on a file at the same time?
1) If I use a full path, I won't be able to move the code around by email or flashdrive, something I puit high value in. Why "/" and not "\", the way Explorer does it?
2) My OS is an updated, genuine version of Windows XP. I think it can handle opening files.
The people on msdn forums said that ios::in means that the file has to exist already. That makes sense, so now we have the problem, anyone have a solution?
What I want to do is this:
1) Look for "hssav.sav" and read the highscores for display, If it doesn't exist, create it with 0s for high scores.
2) Display the scores throughout the game.
3) When the player dies (and they will, ha ha), compare their scores. If the player did better than the last high score, write his score to "hssav.sav".
If I can only open the fstream object in ios::out and ios::binary, will I be able to read from it? Maybe I should create more than one object?
Why not try to open the file for reading, if it fails create the file and proceed with opening with ios:in?
1) If I use a full path, I won't be able to move the code around by email or flashdrive, something I puit high value in. Why "/" and not "\", the way Explorer does it?
That was just to check if you could open the file. That way you would have known if you could open the file or not. Also, in the C language, you use / to separate paths.
My OS is an updated, genuine version of Windows XP. I think it can handle opening files.
He didn't mean that the operating system was unable to open files. He meant he wasn't sure it could handle opening a file for reading and writting in the way you did it at the same time. But, in this case, yes, it can.
When opening a binary file, you open with ios::binary | ios::in | ios::out as to not overwrite data, and to allow you to read and write at the same time. It is kind of like appending, only you still read/write from the beginning of the file.
The \ character is just a pain in the ass to deal with. Use / because A) it works, and B) it's not a pain in the ass. If you want to use the full path without having to set it constant within code (such as in a #define statement), then you can get the path from argv[0].
| 1 | fstream sav; |
| 2 | #define SAV_FILE "hssav.sav" |
| 3 | |
| 4 | int main() |
| 5 | { |
| 6 | /* init allegro here */ |
| 7 | |
| 8 | /* do some junk here that would make us want |
| 9 | to bring up the highscores */ |
| 10 | if( !file_exists(SAV_FILE, 0, NULL) ) |
| 11 | create_highscores(); |
| 12 | |
| 13 | sav.open(SAV_FILE, ios::binary | ios::in | ios::out); |
| 14 | if( sav.is_open() ) |
| 15 | /* somehow extract your data from the file now */ |
| 16 | else |
| 17 | allegro_message("Error opening file for reading: %s", SAV_FILE); |
| 18 | |
| 19 | return 0; |
| 20 | } |
| 21 | |
| 22 | void create_highscores() |
| 23 | { |
| 24 | fstream nf; |
| 25 | nf.open(SAV_FILE, ios::binary | ios::out); |
| 26 | |
| 27 | if( nf.is_open() ) |
| 28 | { |
| 29 | // fill the file with 0s |
| 30 | } |
| 31 | else |
| 32 | { |
| 33 | // uh-oh! |
| 34 | allegro_message("Error opening file for writing: %s", SAV_FILE); |
| 35 | } |
| 36 | |
| 37 | // we close it, even though the default destructor |
| 38 | // does so automatically. why? don't be a lazy |
| 39 | // programmer and expect your code to run! |
| 40 | nf.close(); |
| 41 | } |
Thanks, now its opening just fine. However, I think I'm writing or reading incorrectly. Here is my code (this takes place in the middle of a project, this isn't all of the code):
| 1 | |
| 2 | //global |
| 3 | #define S_FILE "hssav.sav" |
| 4 | |
| 5 | fstream sav; |
| 6 | |
| 7 | void create_hsfile(); |
| 8 | |
| 9 | //main |
| 10 | if(!file_exists(S_FILE, 0, NULL)) |
| 11 | create_hsfile(); |
| 12 | |
| 13 | sav.open(S_FILE, ios::binary|ios::in|ios::out); |
| 14 | |
| 15 | int hs_score, hs_level; |
| 16 | DEF /* typedef const int DEF */ recsize (2 * sizeof(int)); |
| 17 | |
| 18 | if(sav.is_open()){ |
| 19 | sav.seekp((difficulty-1)*recsize); //difficulty is 1, 2, or 3 int(I want different highscores per difficulty) |
| 20 | sav.read(reinterpret_cast<char*>(&hs_level), sizeof(int)); |
| 21 | sav.read(reinterpret_cast<char*>(&hs_score), sizeof(int)); |
| 22 | } |
| 23 | |
| 24 | if(sav.is_open()) |
| 25 | textprintf(buffer, font, SCREENW / 2, 0, BLUE, "High Scores = Score=%d, Level=%d", hs_score, hs_level); |
| 26 | else |
| 27 | textprintf(buffer, font, SCREENW / 2, 0, BLUE, "COULD NOT LOAD OR CREATE HIGH SCORE FILE"); |
| 28 | |
| 29 | //player is dead |
| 30 | sav.seekp((difficulty-1)*recsize); |
| 31 | if(score > hs_score){ |
| 32 | sav.write(reinterpret_cast<char*>(&level),sizeof(int)); |
| 33 | sav.write(reinterpret_cast<char*>(&score),sizeof(int)); |
| 34 | } |
| 35 | |
| 36 | sav.close(); |
| 37 | |
| 38 | |
| 39 | //def of create_hsfile |
| 40 | |
| 41 | void create_hsfile(){ |
| 42 | fstream temp; |
| 43 | int n = 0; |
| 44 | |
| 45 | temp.open(S_FILE, ios::binary|ios::out); |
| 46 | |
| 47 | if( temp.is_open() ){ |
| 48 | for(int i = 0; i > 3; ++i){ |
| 49 | temp.write(reinterpret_cast<char*>(&n), sizeof(int)); |
| 50 | temp.write(reinterpret_cast<char*>(&n), sizeof(int)); |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | temp.close(); |
| 55 | |
| 56 | } |
there it is, score and level print some huge number like -33686019, and I'm sure that the actual games score and level are correct.
does it help if I tell you that opening hssav.sav in notepad leavs me with a blank file?
Well, a reinsterpret_cast to a char*? Don't you want a static_cast?
No, anything I've ever read says reinterpret_cast. Besides, switching 6 r casts to s casts gave me 6 compiler errors that weren't there before. I think static cast is only for declared vaiables.
Okay, you're right. But you do call seekp (seek the put pointer) and then use the get pointer for access. Try seekg instead
Sorry I haven't posted for so long. In Orlanda (not near my computer in Miami) attending the Florida FFA state convention. I changed the seek thingy to seekg before I read from the file and it still doesn't work. Which seekps should be seekgs?
hmm, the only thing I can think of is maybe opening the file in append mode instead of truncate:
ios::ate(this is a maybe)
In Orlanda (not near my computer in Miami) attending the Florida FFA state convention.
Orlando, and did you mean FAA?
Didn't work. Maybe it helps if I tell you that the following code is repeated once per time the player plays. Basically, I put all the code that needs to be repeated every time the player dies into a function bool game(). it returns true if it needs to be run again. Main now looks like this
//includes int main{ //initialize allegro, load images, open file or create bool again; do{ again = game(); }while(game); // close down }
Works like a charm. the following code resides in game and not main.
| 1 | if(sav.is_open()){ |
| 2 | sav.seekp((difficulty-1)*recsize); //difficulty is 1, 2, or 3 int(I want different highscores per difficulty) |
| 3 | sav.read(reinterpret_cast<char*>(&hs_level), sizeof(int)); |
| 4 | sav.read(reinterpret_cast<char*>(&hs_score), sizeof(int)); |
| 5 | } |
| 6 | |
| 7 | if(sav.is_open()) |
| 8 | textprintf(buffer, font, SCREENW / 2, 0, BLUE, "High Scores = Score=%d, Level=%d", hs_score, hs_level); |
| 9 | else |
| 10 | textprintf(buffer, font, SCREENW / 2, 0, BLUE, "COULD NOT LOAD OR CREATE HIGH SCORE FILE"); |
| 11 | |
| 12 | //player is dead |
| 13 | sav.seekp((difficulty-1)*recsize); |
| 14 | if(score > hs_score){ |
| 15 | sav.write(reinterpret_cast<char*>(&level),sizeof(int)); |
| 16 | sav.write(reinterpret_cast<char*>(&score),sizeof(int)); |
| 17 | } |
And I did mean FFA(Future Farmers of America). Its an agricultural youth organization that I'm involved in for school. I went to recieve an award for excellent poultry judging and to have fun.
sav.seekp((difficulty-1)*recsize); //difficulty is 1, 2, or 3 int(I want different highscores per difficulty) sav.read(reinterpret_cast<char*>(&hs_level), sizeof(int)); sav.read(reinterpret_cast<char*>(&hs_score), sizeof(int));
You are still using seekp, which seeks what you write to, not where you read from.
I went to recieve an award for excellent poultry judging and to have fun.
You were judged on your ability to judge poultry?
Also, in the C language, you use / to separate paths.
Not the language. The language itself doesn't even know such things as files exist. Quite a lot of libraries (including stl and libc) use '/' though. The win32 api, however, doesn't. (Why one would use that for opening files is a different story though).
Sorry I should have edited the post. After you said "try seekg instead", I did change it.