again problems with fstream

can some one plaes tell me what's wrong with my code?
it copiles but when i use it : it reads an int , a char , and a strig then writes them to a file and closes the file . then it opens the file for riding it should read the int , char and string it has preaviusly writen and display them but after displaying them it also displaies lot of charaters and gives an eror ;

here is the code :

#include<iostream>
#include<fstream>
#include<string>
using namespace std;
class clasa
{public:
int n;
char t;
string st;
};
void citeste(void)
{
clasa a;
fstream file("file.tx", ios::in);
if( file.is_open()) cout<<"\n la deschis \n";
file.seekg(0);
file.read( (char*)&a, sizeof(clasa) );
cout<<a.n<<a.t<<a.st;
file.close();
}

void scrie(void)
{
clasa a;
fstream file("file.tx", ios::out | ios::trunc);
if( file.is_open()) cout<<"\n la deschis \n";
cin>>a.n>>a.t>>a.st;
file.seekp(0);
file.write( (char*)&a, sizeof(clasa));

file.close();
}

int main(void)
{
//cout<<sizeof(clasa);
scrie();
citeste();
system("PAUSE");
return 0;
}
I've just compiled and run your code on UNIX and it seems OK (apart from the system("PAUSE") as UNIX doesn't have a pause). The only thing I can suggest is putting an endl on your cout (and some spaces)

cout<<a.n<<" "<< a.t<<" "<< a.st << endl;
Last edited on
so your saying that on an UNIX system it works fine?!?!?
that is realy wird!!!
I copiled it whit DEV CPP on XP and VISTA bouth 32 bit an it had the same resoult AFTER DISPLAYING THE NORMAL STAF IT DISPLAYS A LOG STRIG OF CHARACTERS AND WINDOWS REPORTS AN EROR!!!!!

As far as I know it should have the sameresoult idependent of the OS, or not???
can some one compile it on windows or debian pls?
closed account (z05DSL3A)
It works on XP compiled with Visual Studio...

Edit: But craps out when using Dev-C++
Last edited on
That it works at all is a surprise. (bnbertha was just lucky that his global memory space didn't change between the time of read and write.)

In general, you should avoid using fstream.read() and .write(). They are very low-level operations that expose your software to endianness and type-size problems. You can generally do without them.

The best way is to overload the << and >> operators to operate on your class to write and read binary data.
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
class clasa
  {
  public:
    int    n;
    char   t;
    string s;

  friend ostream& operator << ( ostream& outs, const clasa& a );
  friend istream& operator >> ( istream& ins, clasa& a );
  };

ostream& operator << ( ostream& outs, const clasa& a )
  {
  // Manually parse the int into a little-endian byte order
  // Notice how we hardcode the number of bytes per int.
  // Our file will work no matter what OS/hardware we use it with
  for (int cntr = 0, n = a.n; cntr < 4 /*bytes*/; cntr++, n >>= 8)
    outs.put( n & 0xFF );

  // The t is a char == byte...
  outs.put( a.t );
  
  // There are a number of ways to store the string, but we'll
  // just write it as an ASCIIZ for simplicity.
  outs << a.s << '\0';

  return outs;
  }

istream& operator >> ( istream& ins, clasa& a )
  {
  // In the following, we don't care much to check for
  // EOF. That can be determined by the caller after
  // using this routine. If EOF is signaled, then the target
  // 'a' is not guaranteed to contain complete data
  // (which is the same behavior for all other types).

  // Extract that first little-endian, four-byte int
  a.n = 0;
  for (int i = 0; i < 4 /* bytes again */; i++)
    a.n = a.n +(ins.get() << (8 *i));

  // Get t
  a.t = ins.get();

  // Get the ASCIIZ string into a std::string variable
  getline( ins, a.s, '\0' );

  return ins;
  }


Now you can use it responsibly:
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
#include <fstream>
#include <iostream>
#include <limits>
#include <string>

using namespace std;

...

int main()
  {
  clasa a;
  a.n = 42;
  a.t = 'A';
  a.s = "Hello world!";

  ofstream outf( "file.txt", ios::trunc | ios::binary );
  outf << a;
  outf.close();

  clasa b;
  ifstream inf( "file.txt", ios::binary );
  inf >> b;
  inf.close();

  if ((a.n == b.n)
  and (a.t == b.t)
  and (a.s == b.s))
    cout << "success!\n";
  else
    cout << "failure...\n";

  // Please don't use 'system("PAUSE")' in production code.
  cout << "Press ENTER to continue...";
  cin.ignore( numeric_limits<streamsize>::max(), '\n' );

  return 0;
  }

JSYK, main(void) is not valid C++. Make sure you compile with all warnings enabled.

If you plan to work with binary data, make sure you open your streams in binary mode. The design of the STL has some significant failures in dealing with binary vs. text mode streams, so be warned -- always use binary files with binary I/O.

Hope this helps.

@bnbertha
You can try

system( "read -p \"Press any key to continue...\"" );

;-)
Hmm, considering the responses while I was composing mine, I suppose I ought to explain why it fails...

A std::string is an object, which is basically a fancy wrapper for a pointer to a dynamically managed array of char.

The memory manager never guarantees that things need to be allocated in the same place twice.

So even if you write and read the same bits into the std::string container object, there is no guarantee that the memory manager hasn't used your actual string data in some other way.

And anyway, when you read the string, whatever it points to is not currently under the auspices of the mm, so what you've got is a dangling pointer.


The moral: Don't read and write objects with binary I/O.
Always overload for proper serialization.

Hope this helps.
Topic archived. No new replies allowed.