Help with fstream

Pages: 12
Hi, I am a newcomer to C++ and the forum and recently I have been spending most my time making a simple RPG game. My most recent implementation was going to be a load/save feature, and through googling this I figured exporting the variables to a save file through ofstream and importing them again through ifstream was a good idea. Please correct me if I am wrong there.

The problem is whenever I try to compile it, it doesn't like the exporting bit..., this is the code it doesn't like:

1
2
3
4
else if(MainMenu==6){
        ofstream file("save.sav");
        file >> PlayerHealth>>"\n">>PlayerMaxHealth>>"\n">>PlayerDamage>>"\n">>PlayerStrength>>"\n">>PlayerDefence>>"\n">>PlayerGold>>"\n">>VictoryCount>>"\n">>WeaponDamage>>"\n">>ShieldDefence>>"\n">>Experience>>"\n">>Level;
        }


and this is the error it comes up with:

C:\Users\owner\Documents\Simple RPG game\main.cpp|439|error: no match for 'operator>>' in 'file >> PlayerHealth'|

What am I doing wrong? Thanks!
You're using the extraction operator, not the insertion operator
Change >> to <<
Oh, yeah. Forgot about that...

But now that I've changed it loading no longer works. I assume that if ofstream requires << then ifstream requires >>, right? So this is what happens with loading. Here's the problem code:

1
2
3
4
else if(MainMenu==7){
        ifstream file("gamesave.sav");
        file >> PlayerHealth>>"\n">>PlayerMaxHealth>>"\n">>PlayerDamage>>"\n">>PlayerStrength>>"\n">>PlayerDefence>>"\n">>PlayerGold>>"\n">>VictoryCount>>"\n">>WeaponDamage>>"\n">>ShieldDefence>>"\n">>Experience>>"\n">>Level;
        }


and here's the error:

C:\Users\owner\Documents\Simple RPG game\main.cpp|444|error: no match for 'operator>>' in 'file.std::basic_ifstream<char, std::char_traits<char> >::<anonymous>.std::basic_istream<_CharT, _Traits>::operator>> [with _CharT = char, _Traits = std::char_traits<char>](((int&)(& PlayerHealth))) >> "\012"'|
You can't use input like you would output. Think about using cout and cin, and ask yourself if your code up there makes any sense.

EDIT:
Some new lines in your code would be cool, thats quite the long line. Kind of annoying to have to scroll right and left to read it
Last edited on
Ok thanks, but I still don't get what you mean. The only big difference between cout and cin for me at the moment is the >> and <<...

I think adding the new lines in my code would be pretty helpful, haha.

But please could you show me an example which I can base my code from? Thanks.
No problem, but think about this. When you output data to some medium, what are you doing? You are taking some variable or literal and writing it so you can see it somewhere (this could be a window, console, terminal, file, etc.). You can output in all sorts of ways, using escape charaters (ie \n), spaces, tabs, literals, variables, whatever you want really.
Now with input, what are we doing? We are taking some specified area of a medium, and reading data from it into a variable generally (You can also take input and do nothing at all with it, but thats not important). When you are inputting, you are sayin "Ok computer, take this segment of information right here, and store it in this". Whenever you use the extraction operator, it must be followed by a variable that you want this data stored in.

Now with the standard cin, it will read data from the stream, until cin hits its delimiter value, which for cin is a blank space. Now, it also wont actually process the data until it hits a newline character.
Something like this
cin >> v1 >> v2 >> v3;
Works just fine, because each extraction operator is followed by a variable each time. When this happens, it will read all data into v1 until the first blank space is encountered, and then it will read into v2 until the 2nd blank space, and so on.

These same ideas carry over to file I/O. When you are extracting data from a file, you must follow an extraction operator by a variable. So something like
file >> PlayerHealth>>"\n"
Will not work because you just put a literal after an extraction operator, so your compiler is getting all pissy.



http://www.cplusplus.com/reference/iostream/ifstream/
Have a look through this. Look at the way ifstreams/ofstreams are used:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <iostream>		// cout
#include <conio.h>		// _kbhit()
#include <fstream>		// files
#include <string>		// strings

int main( int argc, const char *argv[] )
{
	char var1[] = "using";
	char var2[] = "fstream";
	char var3[] = "files";

	//output( save to file )
	std::ofstream ofile( "text.txt", std::ios::out );

	//if the file is not open...
	if( ! ofile.is_open() )
	{
		//you can do other stuff here, if need be.
		std::cout << "Error opening file...\n";
		return EXIT_FAILURE;
	}
	else
	{
		//save to file, seperated by spaces
		ofile << var1 << ' ' << var2 << ' ' << var3;

		//close the file after use!
		ofile.close();
	}

	//input file( read from file )
	std::ifstream ifile( "text.txt", std::ios::in );

	if( ! ifile.is_open() )
	{
		std::cout << "Error opening file...\n";
		return EXIT_FAILURE;
	}
	else
	{
		//create a string to save the line of text to
		std::string input;

		//loop until the end of the file
		while( ! ifile.eof() )
		{
			//read from file, seperated by spaces
			//this will get a line from a the file and stop at
			//the space( delimiter ). This will then be saved
			//to the string 'input'. The space will be striped.
			std::getline( ifile, input, ' ' );

			//cout each input
			//because the delimiter above was a space.
			//add spaces back in between inputs.
			std::cout << input << ' ';

			//output will be:
			//using fstream files

			//do some conversion here, to save from string to your variable type
			//i.e. stringstream etc.
		}

		//close the file after use!
		ifile.close();
	}	

	//press any key to exit...
	std::cout << "\n\nPress any key to exit . . .\n";

	while( ! _kbhit() )
	{ /* do nothing - wait for key press */ }
	
	return 0;
}


EDIT:
I've added line 58 & 59.
Last edited on
I think I get what you are saying, like for output it just takes what you say and writes it onto the file, but with input you need to tell it what to take and then tell it where to put it. Is that right?

And you say each >> makes it think it is a new thing to read, yes?

So am I right in saying that:

file >> PlayerHealth>>"\n"

would be better as:

file >> PlayerHealth"\n"

therefore several variables can be read like this:

file >> PlayerHealth"\n" >> PlayerMaxHealth"\n" >> PlayerDamage"\n" >> and so on

is that right?
Well, not really. With each new extraction operator, is a new read yes. So...
1
2
3
4
5
6
//These two are equivalent
file >> v1 >> v2 >> v3;

file >> v1;
file >> v2;
file >> v3;


You also can't use file >> PlayerHealth >> "\n"; because you are following an extraction operator by a literal. Think about exactly what is happening. When you use an extraction operator, you are telling the computer to take input from a stream object, and store it into a variable.

stream >> variable;

So you are trying to store data into a literal, which isnt possible. A literal is a literal, its defined in the program.

stream >> "Hello"; What is this? It makes no sense to a computer. And it shouldnt once you get the hang of I/O. You are saying this when you write this: "Ok computer, take that data that's stored in that stream, and put it into 'Hello'". It just doesn't work.

And also, file >> PlayerHealth"\n"; wouldn't work either. I'm not sure what you're trying to do here. But it looks like you're trying to add a newline to PlayerHealth, which makes no sense again. PlayerHealth is a variable defined in your program, and all you are doing is simply reading data from a file and storing it into that. If you want to display it on it's own line, you do that when you handle output
@Lynx876

So is the difference between my code and the code you posted the fact that I am not doing anything to open or close the file first?

@ResidentBiscuit

Well at least I am making progress a little bit, haha.

What I am trying to do is replace the value of PlayerHealth with the number that is on the first line of the file "gamesave.sav", so that I can save a game, let it write all my stats to the save file and then load it later so instead of getting the default stats the game gives me I get the stats that I wrote to the save file.

So what am I doing instead that is wrong?
Last edited on
You should not use "\n" when you read from the file.
ofstream file("save.sav");
That code actually opens the file. My if statement just checks if the file was found and opened.

To replace PlayerHealth with the first line of the file, I'd do something like the following:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
std::string input;

//read up to a '\n' ( new line char( ENTER ) )
std::getline( ifile, input, '\n');

//Then use stringstream. Guessing PlayerHealth is an int
//create a stringstream object and pass it input
std::stringstream ss( input );

//if the input, in ss, can be saved in to PlayerHealth
if( ss >> PlayerHealth )
    //conversion worked correctly
else
    //failed conversion 


Personally, I'd do it this way. I 'think' I came across problems with doing the following:
ifile >> var1 >> var2;

So I convert it the way I know best now (:
So, it needs to read the file up to the \n, take everything it has read so far and put it into 'input', then put that into a stream and then put that into PlayerHealth? I think I get it now. But with that does it mean I have to put what you wrote for each variable i want to import?
Yes. But you could just make this in to a function:
1
2
3
4
5
6
7
8
int streamInt( std::string i )
{
    std::stringstream ss( i );

    ss >> convertedInt;

    return convertedInt;
}


then you just need to do:
1
2
3
4
5
std::getline( ifile, input, '\n' );
PlayerHealth = streamInt( input )

std::getline( ifile, input, '\n' );
PlayerMaxHealth = streamInt( input )


EDIT:
Just wrote that in FireFox, so it wont compile. But you get the idea. I hope (:
Last edited on
I am a noob with functions so do I need to put that first bit of code at the very start of the program or just above where I will be putting the second bit(s) of code(s)?
You can either write out the whole function above main():
1
2
3
4
5
6
7
8
9
10
11
12
13
int streamInt( std::string i )
{
    /* code */

    return anInt;
}

int main()
{
    /* code */

    return 0;
}


Or, you can make a forward declaration of the function, and write the function after main():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//forward declaration
int streamInt( std::string i );

int main()
{
    /* code */

    return 0;
}

int streamInt( std::string i )
{
    /* code */

    return anInt;
}


When you come to using multiple files( creating seperate .cpp and .h files ), The foward declaration would be needed. That way, you can make a header file( .h ) and have all your #include s in a single file.

includes.h
1
2
3
4
#include <iostream>
#include <string>

int streamInt( std::string i );


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "includes.h" // "" quotes for local files

int main()
{
    /* code */

    std::string input;

    std::getline( file, input, '\n' );

    int i = streamInt( input )

    return 0;
}


streamInt.cpp
1
2
3
4
5
6
7
8
9
10
#include "includes.h"  // "" quotes for local files

int streamInt( std::string i )
{
    std::stringstream ss( i );

    ss >> convertedInt;

    return convertedInt;
}
so put:

1
2
3
4
5
int streamInt( std::string i ){
    std::stringstream ss( i );
    ss >> convertedInt;
    return convertedInt;
}


above main (I am doing the first method for now) and:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
else if(MainMenu==7){
        ifstream file("gamesave.sav");
        std::getline( ifile, input, '\n' );
        PlayerHealth = streamInt( input )

        std::getline( ifile, input, '\n' );
        PlayerMaxHealth = streamInt( input )

        std::getline( ifile, input, '\n' );
        PlayerDamage = streamInt( input )

        std::getline( ifile, input, '\n' );
        PlayerStrength = streamInt( input )

        std::getline( ifile, input, '\n' );
        PlayerDefence = streamInt( input )

        std::getline( ifile, input, '\n' );
        PlayerGold = streamInt( input )

        std::getline( ifile, input, '\n' );
        VictoryCount = streamInt( input )

        std::getline( ifile, input, '\n' );
        WeaponDamage = streamInt( input )

        std::getline( ifile, input, '\n' );
        ShieldDefence = streamInt( input )

        std::getline( ifile, input, '\n' );
        Experience = streamInt( input )

        std::getline( ifile, input, '\n' );
        Level = streamInt( input )

        }


in the main? Just tried to compile that and it doesn't agree with a few bits. In the function above the main the error says:

C:\Users\owner\Documents\Simple RPG game\main.cpp|10|error: variable 'std::stringstream ss' has initializer but incomplete type|

C:\Users\owner\Documents\Simple RPG game\main.cpp|11|error: 'convertedInt' was not declared in this scope|

and in the main where the second code is it comes back with:

C:\Users\owner\Documents\Simple RPG game\main.cpp|454|error: 'ifile' was not declared in this scope|

C:\Users\owner\Documents\Simple RPG game\main.cpp|454|error: 'input' was not declared in this scope|

Something I'm doing wrong I assume?
I forgot to mention, to use stringstream, you need:
#include <sstring>

You have created an ifstream called file and try to read from a file called ifile.
1
2
ifstream file("gamesave.sav");
std::getline( ifile, input, '\n' );


And the other errors, you haven't declared the varibles before trying to use them.
Ok, so changing all the "ifile"s to "file"s fixed that error. For input, should I just declare it as any other variable? If so, what type?

And when adding the <sstring> library it says that library doesn't exist. Something wrong with my compiler?

EDIT:

After googling the problem I replaced <sstring> with <sstream>. This got rid of one of the errors. Is that what you meant?
Last edited on
You just need to declare a string called input.

And by the way, if you have using namespace std;, then you don't need to add 'std::' to the start of things.

I prefer to not add using namespace std;.

And yeah, my bad, I typed it wrong. It's: #include <sstream>
Pages: 12