Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » binary fstram object

Credits go to Elverion and HoHo for helping out!
This thread is locked; no one can reply to it. rss feed Print
binary fstram object
aadfo824
Member #7,265
May 2006

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.

ReyBrujo
Moderator
January 2001
avatar

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.

--
RB
光子「あたしただ…奪う側に回ろうと思っただけよ」
Mitsuko's last words, Battle Royale

Dustin Dettmer
Member #3,935
October 2003
avatar

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?

aadfo824
Member #7,265
May 2006

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?

HoHo
Member #4,534
April 2004
avatar

Why not try to open the file for reading, if it fails create the file and proceed with opening with ios:in?

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

ReyBrujo
Moderator
January 2001
avatar

Quote:

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.

--
RB
光子「あたしただ…奪う側に回ろうと思っただけよ」
Mitsuko's last words, Battle Royale

Elverion
Member #6,239
September 2005
avatar

Quote:

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].

1fstream sav;
2#define SAV_FILE "hssav.sav"
3 
4int 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 
22void 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}

--
SolarStrike Software - MicroMacro home - Automation software.

aadfo824
Member #7,265
May 2006

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 
5fstream sav;
6 
7void 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 
24if(sav.is_open())
25 textprintf(buffer, font, SCREENW / 2, 0, BLUE, "High Scores = Score=%d, Level=%d", hs_score, hs_level);
26else
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 
41void 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?

CGamesPlay
Member #2,559
July 2002
avatar

Well, a reinsterpret_cast to a char*? Don't you want a static_cast?

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

aadfo824
Member #7,265
May 2006

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.

CGamesPlay
Member #2,559
July 2002
avatar

Okay, you're right. But you do call seekp (seek the put pointer) and then use the get pointer for access. Try seekg instead :)

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

aadfo824
Member #7,265
May 2006

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?

CGamesPlay
Member #2,559
July 2002
avatar

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)

Quote:

In Orlanda (not near my computer in Miami) attending the Florida FFA state convention.

Orlando, and did you mean FAA?

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

aadfo824
Member #7,265
May 2006

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 
7if(sav.is_open())
8 textprintf(buffer, font, SCREENW / 2, 0, BLUE, "High Scores = Score=%d, Level=%d", hs_score, hs_level);
9else
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.

CGamesPlay
Member #2,559
July 2002
avatar

Quote:

   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.

Quote:

I went to recieve an award for excellent poultry judging and to have fun.

You were judged on your ability to judge poultry? :P

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

Tobias Dammers
Member #2,604
August 2002
avatar

Quote:

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).

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

aadfo824
Member #7,265
May 2006

Sorry I should have edited the post. After you said "try seekg instead", I did change it.

Go to: