PDA

View Full Version : Read/write data from file



Insomnium
8th December 2010, 21:14
First of all execuse me for my English please. I'm writing a game. High scores will be stored in file reading and writing with QDataStream. Then scores will be shown in table view. There are 3 difficulty levels in my game and all the information will be stored in one file. Everything worked fine for one diff. level, but I've got troubles organizing work with 3 levels. Here is my code:
bool Score::readFile() {
QFile file("score.sc");
QDataStream in(&file);
if (!file.open(QIODevice::ReadOnly)) {
...
return -1;
}

quint16 row;
quint16 column;
QString str;

while (!in.atEnd()) {
in >> row >> column >> str;
if ( !column%2 ) pl[row].plname = str;
else pl[row].plresult = str.toInt();
}
file.close();
return 1;
}

bool Score::writeFile() {
QFile file("score.sc");
if (!file.open(QIODevice::WriteOnly)) {
...
return -1;
}

QDataStream out(&file);

for (int row = 0; row < MAX_ROWS; ++row) {
for (int column = 0; column < MAX_COLUMNS; ++column) {
if ( !column%2 ) {
QString str = pl[row].plname;
out << quint16(row) << quint16(column) << str;
} else {
QString str = QString::number(pl[row].plresult);
out << quint16(row) << quint16(column) << str;
}

}
}
file.close();
return 1;
}
}

And here is what I'm trying to do next for working with 3 difficulty levels:


bool Score::readFile() {
QFile file("score.sc");
QDataStream in(&file);
if (!file.open(QIODevice::ReadOnly)) {
...
return -1;
}

quint16 row;
quint16 column;
QString str;

int block_num = 2; // = difficulty + 1 (testing version)
file.seek(qint64( (sizeof(quint16)*2 + sizeof(QString)) * 15 * block_num ) );
for (int val_red = 0; val_red < 15; ++val_red) {
in >> row >> column >> str;
if ( !column%2 ) pl[row].plname = str;
else pl[row].plresult = str.toInt();
}
file.close();
return 1;
}

bool Score::writeFile() {
QFile file("score.sc");
if (!file.open(QIODevice::WriteOnly)) {
...
return -1;
}

QDataStream out(&file);

int block_num = 2;
file.seek(qint64( (sizeof(quint16)*2 + sizeof(QString)) * 15 * block_num ) );
for (int row = 0; row < MAX_ROWS; ++row) {
for (int column = 0; column < MAX_COLUMNS; ++column) {
if ( !column%2 ) {
QString str = pl[row].plname;
out << quint16(row) << quint16(column) << str;
} else {
QString str = QString::number(pl[row].plresult);
out << quint16(row) << quint16(column) << str;
}

}
}
file.close();
return 1;
}


Let me explain. There are 15 pairs 'name - result' stored in a structure pl for every difficulty level. block_num equals 2 for a while, but later I'll transfer them as function parameters. And at fact file can be divided into 3 parts. I believe my problem is in calculating size of "blocks". But there is something wrong with reading (or even writing) data because I've got unexpected output after read/write operations. Help me please. Thank you.

marcvanriet
9th December 2010, 00:35
Use QXmlStreamReader and QXmlStreamWriter instead. This is quite easy to use. Writing is very easy. Reading requires a bit more coding, but can be very easy also if you know what data fields to expect.

Best regards,
Marc

ChrisW67
9th December 2010, 01:32
Your offset calculation is wrong. The sizeof(QString) is neither the length of the string in bytes nor the size that it would occupy on disk using QDataStream.

Here are some thoughts:

You could read each difficulty block in turn until you found the right one.
You could store three separate files.
You could note the file offset at the start of each difficulty block and store it at the end of the file as an index during writing. During reading, you load the index from the end of the file and use that to more directly address your difficulty block. This can be done at the front of the file with some care.
You could use a text based format like XML and use element IDs to address chunks of the data.

Incidentally, the nested loops don't seem to be a good fit to a list-of-pairs data structure.

Insomnium
9th December 2010, 10:06
Yes, my program worked fine with 3 separated files but I need it to work with one. I decided to use QList to store data. ('difficulty-name-score'). But now I've got one more problem. I can't sort my list by score using qSort() function.
qSort(myList->begin(), myList->end(), qGreater<...>());

How can I handle to pl.score from list in qGreater where pl is a structure 'name-score'?

Thank you and sorry, I should post it into a newbie questions.

ChrisW67
9th December 2010, 22:41
Either provide your pl data structure with an operator<() or provide an external function that provides a similar effect (example in the qSort docs).

Insomnium
10th December 2010, 08:35
Thank you, I already found this way. Qt Assistant is a great thing.