Reading and Writing to Binary Files

D

Daniel Moree

I'm working on a program that must first establish if the file exists in the
program directory then it must open if for reading, read each line and set
the variables then the program goes on about it's buisness.

My problem is all the resources I have found aren't very clear on these
things. All of them open the file then check to see if the stream is open.
Well, the problem with using file.open("filename.dat", ios::in |
ios::binary) is that if the file doesn't exists, it creates it
automatically. I need to see if the file exists, if it doesn't show an error
message, then if the file does exists, open if, read from it, then set the
global program variables. Below is my code so far to try to get this work.

I've marked where I needed help with // Need help here and many question
marks
Hopefully you guys will get a good view of what i'm doing, just a basic
console app in MSVC++ that pulls information in a binary file then if that
is successful allow you to set the variables to something else. Then run the
program again and view the information then set it to something different.

===== MAIN.CPP =====
#include <iostream.h>
#include <fstream.h>
#include <iomanip.h>

// variables
int Box_X;
int Box_Y;
int Box_Z;
float input_X;
float input_Y;
float input_Z;
char* filename = {"main.dat"};

// Functions
bool pullconfig();
bool setconfig();

// main function
int main(){
cout << "Pulling configuration information...\n";
if(pullconfig() == false){
cout << "\nError opening \"main.dat\" file: Does Not Exist!\n";
return 0;
}
cout << "Configuration pulled successfully!\n";
cout << "\nBox_X = " << Box_X << "; Box_Y = " << Box_Y << "; Box_Z = "
<< Box_Z << "\n";
cout << "Set Box_X to: ";
cin >> input_X;
cout << "Set Box_Y to: ";
cin >> input_Y;
cout << "Set Box_Z to: ";
cin >> input_Z;
if(setconfig() == false){
cout << "\nError setting configuration information!\n";
return 0;
}
cout << "\nNew Configuration Set Successfully!";
return 0;
}

bool pullconfig(){
ifstream fin(filename, ios::in | ios::binary);
if(!fin.is_open()){
return(false);
}

// Need Help here for pulling info and setting it to Box_X, Box_Y, and
Box_Z ????????????????????????????????
return(true);
}

bool setconfig(){
ofstream fout(filename, ios::eek:ut | ios:binary);
if(!fout.is_open()){
return(false);
}
fout << "Box_X = " << input_X << "\n";
fout << "Box_Y = " << input_Y << "\n";
fout << "Box_Z = " << input_Z << "\n";
fout.close();
return(true);
}
 
J

Jonathan Mcdougall

I'm working on a program that must first establish if the file exists in the
program directory then it must open if for reading, read each line and set
the variables then the program goes on about it's buisness.

My problem is all the resources I have found aren't very clear on these
things. All of them open the file then check to see if the stream is open.
Well, the problem with using file.open("filename.dat", ios::in |
ios::binary) is that if the file doesn't exists, it creates it
automatically.

This is not the standard behavior.

# include <fstream>

int main
{
std::ifstream ifs("myfile");

if ( ! ifs )
{
// file does not exist or some other error
}
}

I need to see if the file exists, if it doesn't show an error
message, then if the file does exists, open if, read from it, then set the
global program variables. Below is my code so far to try to get this work.

If your standard library does that, change it. If you can't use
implementation-defined functions which will probably give you many more
options, such as checking if a file exists.
===== MAIN.CPP =====
#include <iostream.h>
#include <fstream.h>
#include <iomanip.h>

Non standard.

# include <iostream>
# include <fstream>
# include <iomanip>

using namespace std;

This could be the source of your problem. I put the using declaration
here to make the code work, but do read about its associated problems.
// variables
int Box_X;
int Box_Y;
int Box_Z;
float input_X;
float input_Y;
float input_Z;
char* filename = {"main.dat"};

Global variables are best avoided.
// Functions
bool pullconfig();
bool setconfig();

// main function
int main(){

}

bool pullconfig(){
ifstream fin(filename, ios::in | ios::binary);
if(!fin.is_open()){
return(false);
}

// Need Help here for pulling info and setting it to Box_X, Box_Y, and
Box_Z ????????????????????????????????

I don't know about the file format, but have a look at this.

// file.txt
123
456
789


// main.cpp
# include <iostream>
# include <fstream>
# include <sstream>
# include <string>

int main()
{
std::ifstream ifs("file.txt");
int box_x = 0, box_y = 0, box_z = 0;

if ( ! ifs )
{
std::cout << "There was an error with the file";
return 1;
}

std::string line;
std::istringstream iss;

std::getline(ifs, line);
iss.str(line);
iss >> box_x;

std::getline(ifs, line);
iss.str(line);
iss >> box_y;

std::getline(ifs, line);
iss.str(line);
iss >> box_z;

std::cout << box_x << box_y << box_z;
}

(untested and lots of error checking left out)

Jonathan
 
D

Daniel Moree

Thanks for your help. This is the best response i've gotten yet. I'm using
the C++ Primer Plus Third Edition. I tried using the standard namespace and
i had the same errors so i figured that it wouldn't make a difference
whether I used #include <iostream.h> or #include <iostream> using namespace
std;

I'll try messing with this and see If I can get any of it to work for me.
I'll post back and let you know

Daniel Moree
 
J

Jonathan Mcdougall

I tried using the standard namespace and
i had the same errors so i figured that it wouldn't make a difference
whether I used #include <iostream.h> or #include <iostream> using namespace
std;

The difference is simple : the former is not standard and the latter is.
The next time you get errors when using standard headers, post it here
and we will be able to help you.
I'll try messing with this and see If I can get any of it to work for me.
I'll post back and let you know

Good.


Jonathan
 
D

Daniel Moree

I've messed around with it and checked out my copy of MSDN and can't quit
figure out the error.

this is the file:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

using namespace std;

int main()
{
ifstream fin("main.dat");
int box_x = 0, box_y = 0, box_z = 0;

if(!fin ){
cout << "There was an error with the file\n";
return 1;
} else {
cout << "File found! Printing Contents:\n\n";

string line;
istringstream iss;

getline(fin, line);
iss.str(line);
iss >> box_x;

getline(fin, line);
iss.str(line);
iss >> box_y;

getline(fin, line);
iss.str(line);
iss >> box_z;

cout << "Box_X: " << box_x << "\n";
cout << "Box_Y: " << box_y << "\n";
cout << "Box_Z: " << box_z << "\n";

cout << "\nEnd Of File\n";

return 0;
}
}

contents of my data file:
9
23
3666

Problem: I run it, I pull the Box_X variable, but I don't get the
information from the second line nor the third. Just get 0 or NULL
I though maybe somewhere I would have to change lines in the getline but it
changes on it's own and pulls nothing from the next line,
maybe I need to reset a variable each time or something. Check it out, see
what's up.

Daniel
 
J

Jonathan Mcdougall

Daniel said:
I've messed around with it and checked out my copy of MSDN and can't quit
figure out the error.

this is the file:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

using namespace std;

int main()
{
ifstream fin("main.dat");
int box_x = 0, box_y = 0, box_z = 0;

if(!fin ){
cout << "There was an error with the file\n";
return 1;
} else {
cout << "File found! Printing Contents:\n\n";

string line;
istringstream iss;

getline(fin, line);
iss.str(line);
iss >> box_x;
iss.clear();

getline(fin, line);
iss.str(line);
iss >> box_y;
iss.clear();

getline(fin, line);
iss.str(line);
iss >> box_z;
iss.clear();

cout << "Box_X: " << box_x << "\n";
cout << "Box_Y: " << box_y << "\n";
cout << "Box_Z: " << box_z << "\n";

cout << "\nEnd Of File\n";

return 0;
}
}

contents of my data file:
9
23
3666

Problem: I run it, I pull the Box_X variable, but I don't get the
information from the second line nor the third. Just get 0 or NULL

Calling clear() on the stream resets its state to good. For a reason I
cannot explain (perhaps someone else could enlighten us), the compiler I
use (.net) seems to set the eof bit after reading from the
istringstream. I don't have other compilers handy to test, but calling
clear() should make it work (it does on my machine).

Jonathan
 
K

Karl Heinz Buchegger

Daniel said:
I've messed around with it and checked out my copy of MSDN and can't quit
figure out the error.

this is the file:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

using namespace std;

int main()
{
ifstream fin("main.dat");
int box_x = 0, box_y = 0, box_z = 0;

if(!fin ){
cout << "There was an error with the file\n";
return 1;
} else {
cout << "File found! Printing Contents:\n\n";

string line;
istringstream iss;

getline(fin, line);
iss.str(line);
iss >> box_x;

getline(fin, line);
iss.clear();

iss.str(line);
iss >> box_y;

getline(fin, line);
iss.clear();

iss.str(line);
iss >> box_z;

cout << "Box_X: " << box_x << "\n";
cout << "Box_Y: " << box_y << "\n";
cout << "Box_Z: " << box_z << "\n";

cout << "\nEnd Of File\n";

return 0;
}
}

contents of my data file:
9
23
3666

Problem: I run it, I pull the Box_X variable, but I don't get the
information from the second line nor the third.

You first nead to clear the stringstream.
The simplest thing is: Always use a fresh stringstream object. This
is much less an issue, if you simply put the reading of a value into
a function of its own. (Error handling omitted in the following)

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

using namespace std;

int ReadInt( ifstream& In )
{
int Tmp;
string line;

getline( In, line );
istringstream iss( line );
iss >> Tmp;

return Tmp;
}

int main()
{
ifstream fin("main.dat");
int box_x = 0, box_y = 0, box_z = 0;

if(!fin ){
cout << "There was an error with the file\n";
return EXIT_FAILURE;
}

cout << "File found! Printing Contents:\n\n";

box_x = ReadInt( fin );
box_y = ReadInt( fin );
box_z = ReadInt( fin );

cout << "Box_X: " << box_x << "\n";
cout << "Box_Y: " << box_y << "\n";
cout << "Box_Z: " << box_z << "\n";

cout << "\nEnd Of File\n";

return EXIT_SUCCESS;
}
 
D

Daniel Moree

#include said:
#include <fstream>
#include <sstream>
#include <string>

using namespace std;

int ReadInt( ifstream& In )
{
int Tmp;
string line;

getline( In, line );
istringstream iss( line );
iss >> Tmp;

return Tmp;
}

int main()
{
ifstream fin("main.dat");
int box_x = 0, box_y = 0, box_z = 0;

if(!fin ){
cout << "There was an error with the file\n";
return EXIT_FAILURE;
}

cout << "File found! Printing Contents:\n\n";

box_x = ReadInt( fin );
box_y = ReadInt( fin );
box_z = ReadInt( fin );

cout << "Box_X: " << box_x << "\n";
cout << "Box_Y: " << box_y << "\n";
cout << "Box_Z: " << box_z << "\n";

cout << "\nEnd Of File\n";

return EXIT_SUCCESS;
}

Thank you! I tried using iss.clear() and got nothing, I also tried
iss.remove() and a few other commands i though would work. I was thinking of
creating a class to do this for me. But I guess creating another function
will work and since It doesn't do much and resets everytime it's perfect.
Thanks for this. I really appriciate it guys!!!!

Daniel Moree
 
K

Karl Heinz Buchegger

Jonathan said:
Calling clear() on the stream resets its state to good. For a reason I
cannot explain (perhaps someone else could enlighten us),

Once you know, it is actually very simple.
As always, eof gets set when an attempt is made to read
past the end of the stream.

Now. When you do

iss >> box_y;

How does op>> detect that it has read the whole number:
* When a character is read from the stream that can no
longer belong to that number (such as eg. whitespace or
a character)
* Or when there is nothing more to read.

How is the second case detected: This is the tricky part.
It cannot be detected other then: when a character read operation
fails because of eof. Thus in order to figure out that the number
in the stream has been read completely, the op>> has to drive the
string into an eof state in this case (that is: the stream contains
only the number and nothing else).
 
J

Jonathan Mcdougall

Karl said:
Once you know, it is actually very simple.
As always, eof gets set when an attempt is made to read
past the end of the stream.

Now. When you do

iss >> box_y;

How does op>> detect that it has read the whole number:
* When a character is read from the stream that can no
longer belong to that number (such as eg. whitespace or
a character)
* Or when there is nothing more to read.

How is the second case detected: This is the tricky part.
It cannot be detected other then: when a character read operation
fails because of eof. Thus in order to figure out that the number
in the stream has been read completely, the op>> has to drive the
string into an eof state in this case (that is: the stream contains
only the number and nothing else).

Perfect explanation as usual, thank you.


Jonathan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,154
Members
46,701
Latest member
XavierQ83

Latest Threads

Top