You are not logged in.

Dear visitor, welcome to QtForum.org. If this is your first visit here, please read the Help. It explains in detail how this page works. To use all features of this page, you should consider registering. Please use the registration form, to register here or read more information about the registration process. If you are already registered, please login here.

1

Thursday, January 21st 2010, 1:45am

c structure & Qfile

Hi all,

Anyone knows how to write a c struct into Qfile and extract them?

below is a sample struct to be written to a file.

Source code

1
2
3
4
typedef struct user {
    Qstring user;
    QString pass;
} user;


Source code

1
2
3
QFile mapfile(filename);
mapfile.open(QIODevice::ReadWrite);
//how to proceed from here?

pitonyak

Trainee

  • "pitonyak" is male

Posts: 57

Location: Columbus, Ohio, USA

  • Send private message

2

Thursday, January 21st 2010, 8:09pm

Consider for a moment what is stored in the structure. If the structure contained data that was stored directly in the structure (such as an integer), you might be able to write the block of memory directly to disk - although this is fraught with peril for reasons that I will not mention here.

In your case, your best bet is likely to write your strings individually and then read them individually. I have not tested the following code to write your data.

Source code

1
2
3
4
5
6
7
QFile mapfile(filename);
if (!mapfile.open(QIODevice::WriteOnly | QIODevice::Text))
  return;

     QTextStream out(&mapfile);
     out << x.user << "\n";
     out << x.pass << "\n";


Now, what might it look like to read the file? Again, untested code

Source code

1
2
3
4
5
6
7
QFile mapfile(filename);
if (!mapfile.open(QIODevice::ReadOnly | QIODevice::Text))
  return;

QTextStream in(&mapfile);
x.user = in.readLine();
x.pass = in.readLine();


This contains very little test code and such, and I did not hold the file open and then move back to where I had written... This should be considered pretty standard stuff.

3

Friday, January 22nd 2010, 12:39am

actually the struct that I placed is just a simple one. I have a more complex struct which contains qlist of other struct and other stuff. so I was trying to place the whole c struct into the file instead of individual items into the file.

Is it possible?

pitonyak

Trainee

  • "pitonyak" is male

Posts: 57

Location: Columbus, Ohio, USA

  • Send private message

4

Friday, January 22nd 2010, 3:36am

In general, the answer is no. With a simple struct, you can perform a binary dump of Memory, but this will not work for your example.

Take a look at
  • http://lists.trolltech.com/qt-interest/2005-09/thread00937-0.html
  • http://doc.trolltech.com/4.6/qdatastream.html
  • http://doc.trolltech.com/4.6/datastreamformat.html
In each of these, the assumption is that you will stream these things out one member at a time. The saving item may be that the data stream class knows about some of the QT container classes, so you may not need to enumerate all of your classes if the types are streamable. That said, depending on the contained types, you can likely set them so that they can be serialized. If you try this out, check to see if it is possible to stream a container with your own data types inside.

5

Friday, January 22nd 2010, 8:20am

for complex structure or if often used, you could define sierialization operators

eg:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// .h file
class User
{
    QString name;
    QString pass;
    friend QDataStream & operator << ( QDataStream & s, const User & u );
    friend QDataStream & operator >> ( QDataStream & s, User       & u );
}:

// friends operators need to be declared outside of the class
QDataStream & operator << ( QDataStream & s, const User & u );
QDataStream & operator >> ( QDataStream & s, User       & u );

// .cpp file
QDataStream & operator << ( QDataStream & s, const User & u )
{
    return( s << u.name << u.pass );
}
QDataStream & operator >> ( QDataStream & s, User & u )
{
    return( s >> u.name >> u.pass );
}

pitonyak

Trainee

  • "pitonyak" is male

Posts: 57

Location: Columbus, Ohio, USA

  • Send private message

6

Friday, January 22nd 2010, 3:07pm

Very similar to what I usually do, but I typically choose to not use friend...

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// .h file
class User
{
    QString name;
    QString pass;
    QDataStream& printIt( QDataStream & s ) const;
    QDataStream& readIt( QDataStream & s );
}:

// friends operators need to be declared outside of the class
QDataStream & operator << ( QDataStream & s, const User & u ) { return u.printIt(s); }
QDataStream & operator >> ( QDataStream & s, User       & u ) { return u.readIt(s); }

// .cpp file
QDataStream& User::printIt( QDataStream & s ) const
{
    return( s << name << pass );
}

QDataStream& User::readIt( QDataStream & s )
{
    return( s >> name >> pass );
}

Another item of note is that you can add methods to a struct. The only difference between a structure and a class in C++ is what items default to public and private.

For a struct, the default access and inheritance is public, and on a class it is private. That is the difference. Strange, huh...

7

Sunday, January 24th 2010, 11:21pm

I got some answers from another forum for this question.

In fact I am trying to place some complex struct

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct place {
    QString placename;
    QString x;
    QString y;
};

struct group {
    QString grpname;
    QList<place> building;
};

struct mapinfo {
    QString map_path;
    QList<group> grp;
};


according to someone, he says its not possible and I can use SQLite database to do it. I just want to see if there is another way.

pitonyak

Trainee

  • "pitonyak" is male

Posts: 57

Location: Columbus, Ohio, USA

  • Send private message

8

Monday, January 25th 2010, 3:01am

In general, a database is not likely to give it to you for free either. You seem to ask the same question over and over again. To be clear, it is trivial to persist the data to a file. The trick, however, is that it is not a single line. You can not simply dump a binary blob containing complex structures into a file (if they contain pointers).

Source code

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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <QtCore/QCoreApplication>
#include <QList>
#include <QString>
#include <QFile>
#include <QTextStream>


struct place {
	QString placename;
	QString x;
	QString y;

	place()
	{
	}

	place(const QString& p1, const QString& p2, const QString& p3) : placename(p1), x(p2), y(p3)
	{
	}

	QTextStream& print(QTextStream& os) const
	{
  	os << placename << "\n" << x << "\n" << y << "\n";
  	return os;
	}
	QTextStream& read(QTextStream& os)
	{
  	placename = os.readLine();
  	x = os.readLine();
  	y = os.readLine();
  	return os;
	}
};

struct group {
	QString grpname;
	QList<place> building;

	QTextStream& print(QTextStream& os) const;
	QTextStream& read(QTextStream& os);
};

struct mapinfo {
	QString map_path;
	QList<group> grp;
};


QTextStream& operator<<(QTextStream& os, place p)
{
  return p.print(os);
}

QTextStream& operator<<(QTextStream& os, group g)
{
  return g.print(os);
}

QTextStream& group::print(QTextStream& os) const
{
  os << grpname << "\n";
  os << building.count() << "\n";
  foreach (place p, building)
  {
	os << p;
  }
  return os;
}

QTextStream& operator>>(QTextStream& os, place& p)
{
  return p.read(os);
}

QTextStream& operator>>(QTextStream& os, group& g)
{
  return g.read(os);
}

QTextStream& group::read(QTextStream& os)
{
  bool ok;
  building.clear();
  grpname = os.readLine();
  int cnt = os.readLine().toInt(&ok, 10);
  for (int i=0; i<cnt; ++i)
  {
	place p;
	os >> p;
	building << p;
  }
  return os;
}


int main(int argc, char *argv[])
{
  group x;
  x.grpname = "GROUP Name";

  // Add two places into the list.
  x.building << place("one", "two", "three") << place("four", "five", "six");


  QString fileName("tmp.txt");
  QFile file(fileName);

  // At this point, decide if you want to use a binary file, or a text file.
  file.open(QIODevice::WriteOnly | QIODevice::Text);
  QTextStream os1(&file);
  os1 << x;
  file.close();

  group y;
  file.open(QIODevice::ReadOnly | QIODevice::Text);
  QTextStream is1(&file);
  is1 >> y;
  file.close();
  qDebug(qPrintable(QString("group name:%1 with %2 places").arg(y.grpname).arg(y.building.count())));
  foreach (place p, y.building)
  {
	qDebug(qPrintable(QString("   +(%1)(%2)(%3)").arg(p.placename).arg(p.x).arg(p.y)));
  }

  return 0;
}

pitonyak

Trainee

  • "pitonyak" is male

Posts: 57

Location: Columbus, Ohio, USA

  • Send private message

9

Monday, January 25th 2010, 3:02am

I assume that you are a new programmer, so I hope that the working example above helps you some.

10

Tuesday, January 26th 2010, 2:07am

Thx. I will try it out. you are right. I am new to object oriented programming as well as qt.

11

Tuesday, January 26th 2010, 2:40am

thanks for the help. I tried it out under a single file it works. but I can't seems to integrate it into my app.

all of my struct is in a header file call common.h and my application is in MainWindow.cpp.

Which functions should I place into the common and which to mainwindow?

if I place all of the functions except main into common.h, I got the

multiple definition of `operator<<(QTextStream&, place)'
multiple definition of `operator<<(QTextStream&, group)'
multiple definition of `group::print(QTextStream&) const'
multiple definition of `operator>>(QTextStream&, place&)'
multiple definition of `operator>>(QTextStream&, group&)'
multiple definition of `group::read(QTextStream&)'

one more question, what should I change if I want it to support pointer of group and place?

This post has been edited 1 times, last edit by "eva2002" (Jan 26th 2010, 2:54am)


pitonyak

Trainee

  • "pitonyak" is male

Posts: 57

Location: Columbus, Ohio, USA

  • Send private message

12

Tuesday, January 26th 2010, 2:58am

I guessed that might be the case...

The reasons that the function is defined multiple times, is because it is defined every time that that the included file is encountered. So, you should have something at the top and bottom of every include file that prevents items from being included multiple times for the same file. As an example, you would probably define each structure, or perhaps all those structures, in a single include file. Then, the the include file is structured something like this:

Source code

1
2
3
4
5
6
#ifndef PLACES_H
#define PLACES_H

this is where your primary definitions go

#endif


Your .h file contains the following:

Source code

1
2
3
4
QTextStream& operator<<(QTextStream& os, place p)
{
    return p.print(os);
}


This defines a global function that calls the print method on the place structure. As written, every file that includes your .h file, then has a copy of this method inside it. In other words, you have multiple copies of it. This is a problem. To avoid this, for this very short method, make this simple method inline and keep it in the .h file.

Source code

1
2
3
4
inline QTextStream& operator<<(QTextStream& os, place p)
{
    return p.print(os);
}

Your .h file also contains a few longer methods. These should go in a .cpp file. This includes the read and print methods.
Ponder why this is. If you do not understand, then ask.

13

Tuesday, January 26th 2010, 3:36am

thx. after placing inline, the errors are cleared. Just ignore the other question i have on the pointers. I got it cleared.