qt qdatastream 讀寫文件
我們使用自定義的二進制格式來實現(xiàn)Spreadsheet文件的保存和讀取。我們用QFile和QDataStream這兩個類來實現(xiàn),它們一起提供了平臺無關(guān)的二進制I/O。
首先是保存文件的代碼:
bool Spreadsheet::writeFile(const QString &fileName)
{
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
QMessageBox::warning(this, tr("Spreadsheet"),
tr("Cannot write file %1: %2.")
.arg(file.fileName())
.arg(file.errorString()));
return false;
}
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_1);
out << quint32(MagicNumber);
QApplication::setOverrideCursor(Qt::WaitCursor);
for (int row = 0; row < RowCount; ++row) {
for (int column = 0; column < ColumnCount; ++column) {
QString str = formula(row, column);
if (!str.isEmpty())
out << quint16(row) << quint16(column) << str;
}
}
QApplication::restoreOverrideCursor();
return true;
}
{
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
QMessageBox::warning(this, tr("Spreadsheet"),
tr("Cannot write file %1: %2.")
.arg(file.fileName())
.arg(file.errorString()));
return false;
}
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_1);
out << quint32(MagicNumber);
QApplication::setOverrideCursor(Qt::WaitCursor);
for (int row = 0; row < RowCount; ++row) {
for (int column = 0; column < ColumnCount; ++column) {
QString str = formula(row, column);
if (!str.isEmpty())
out << quint16(row) << quint16(column) << str;
}
}
QApplication::restoreOverrideCursor();
return true;
}
函數(shù)writeFile()由MainWindow::saveFile()調(diào)用,把文件保存到磁盤上。如果保存成功返回true,否則返回false。
首先我們使用給定的程序名創(chuàng)建一個QFile對象,調(diào)open()打開這個文件準備寫入。同時創(chuàng)建一個QDataSteam對象來操作QFile對象,將數(shù)據(jù)寫入文件中。
在寫數(shù)據(jù)之前,我們將程序的光標換成等待形式,數(shù)據(jù)寫完后恢復原來的鼠標形狀。函數(shù)結(jié)束時,QFile的析構(gòu)函數(shù)把文件自動關(guān)閉。
QDataStream支持基本的C++類型,也支持多種Qt類型。語法和標準C++<iostream>類是一樣的。例如:
Out<<x<<y<<z;把變量x,y,z寫入數(shù)據(jù)流。
In>>x>>y>>z; 從數(shù)據(jù)流中讀取數(shù)據(jù)到x,y,z中。在不同的平臺上,基本的C++類型如short,char,int,long,long long會有不同的字長。最好把它們轉(zhuǎn)換為qint8,quint8,qint16,quint16,qint32,quint32,qint64,quint64,這些類型能確保字長是不隨平臺改變的。
Spreadsheet程序的文件格式非常簡單。一個Spreadsheet文件開頭部分是一個32位的標識數(shù)字(MagciNumber,在spreadsheet.h中定義的,一個二進制的隨機數(shù)),這個數(shù)字后面是一系列的數(shù)據(jù)塊,包括一個單元格的行號,列號和公式組成。為了節(jié)省空間,不保存空的單元格。
數(shù)據(jù)類型的二進制表示由類QDataStream決定。如:quint16表示按big-endian順序保存為兩個字節(jié)。一個QString類型表示是字符串的長度后面接著Unicode碼組成。
自Qt1.0以來,Qt數(shù)據(jù)類型的二進制表示有了很大變化。在未來的Qt版本中還可能有更多的改變,默認QDataStream使用最近的Qt版本的二進制格式(version 7 in Qt 4.1),但是它可以讀取以前的版本。為了程序用新的Qt版本重新編譯后能夠更好的兼容,我們顯式的給出QDataStream使用的版本為7(QDataStream::Qt_4_1定義為常量7)
QDataStream可以支持多種類型。如QFile,QBuffer,QProcess,QTcpSocket或者QUdpSocket。Qt還提供了類QTextStream能夠讀寫文本文件。第12章詳細介紹這些類。
讀取文件如下:
bool Spreadsheet::readFile(const QString &fileName)
{
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::warning(this, tr("Spreadsheet"),
tr("Cannot read file %1: %2.")
.arg(file.fileName())
.arg(file.errorString()));
return false;
}
QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_1);
quint32 magic;
in >> magic;
if (magic != MagicNumber) {
QMessageBox::warning(this, tr("Spreadsheet"),
tr("The file is not a Spreadsheet file."));
return false;
}
clear();
quint16 row;
quint16 column;
QString str;
QApplication::setOverrideCursor(Qt::WaitCursor);
while (!in.atEnd()) {
in >> row >> column >> str;
setFormula(row, column, str);
}
QApplication::restoreOverrideCursor();
return true;
}
{
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::warning(this, tr("Spreadsheet"),
tr("Cannot read file %1: %2.")
.arg(file.fileName())
.arg(file.errorString()));
return false;
}
QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_1);
quint32 magic;
in >> magic;
if (magic != MagicNumber) {
QMessageBox::warning(this, tr("Spreadsheet"),
tr("The file is not a Spreadsheet file."));
return false;
}
clear();
quint16 row;
quint16 column;
QString str;
QApplication::setOverrideCursor(Qt::WaitCursor);
while (!in.atEnd()) {
in >> row >> column >> str;
setFormula(row, column, str);
}
QApplication::restoreOverrideCursor();
return true;
}
函數(shù)readFile()和writeFile()很相似。這次文件的打開方式為QIODevice::ReadOnly而不是QIODevice::writeOnly。設(shè)置QDataStream的版本為7。寫文件和讀文件的版本必須一致。
如果文件的magic number號是正確的,調(diào)用clear()清空所有的表格,因為文件中只是保存了非空的單元格數(shù)據(jù),不能保證所有的單元格都會被設(shè)置,所以必須確保再讀取單元格數(shù)據(jù)前所有的表格要清空。
浙公網(wǎng)安備 33010602011771號