欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

QT中QDataStream二進(jìn)制數(shù)據(jù)讀寫的實現(xiàn)

 更新時間:2022年08月22日 09:58:25   作者:求道玉  
本文主要介紹了QT中QDataStream二進(jìn)制數(shù)據(jù)讀寫的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

Qt中的QDataStream類為我們的程序提供了讀寫二進(jìn)制數(shù)據(jù)的能力。一個數(shù)據(jù)流如果是二進(jìn)制編碼的數(shù)據(jù)流,那么它肯定是與計算機(jī)的操作系統(tǒng)、CPU或者字節(jié)序無關(guān)的。例如,一個數(shù)據(jù)流是在一個運(yùn)行Windows系統(tǒng)的PC機(jī)上被寫入的,那么它照樣可以在一臺運(yùn)行Solaris的Sun SPARC的機(jī)器上被讀取出來。同樣,我們也可以使用QDataStream去讀寫原生的未編碼的二進(jìn)制數(shù)據(jù)。

QDataStream類實現(xiàn)了序列化C++的基本數(shù)據(jù)類型的功能,比如char,short,int,char* 等等。如果要序列化更復(fù)雜的數(shù)據(jù)類型,可以將復(fù)雜數(shù)據(jù)類型分解成獨(dú)立的基本數(shù)據(jù)類型分別進(jìn)行序列化。

一個數(shù)據(jù)流往往需要一個QIODevice配合使用。因為QIODevice代表了一個可以從中讀取數(shù)據(jù)或向其寫入數(shù)據(jù)的輸入輸出設(shè)備。我們最常常見的QFile文件類就是一種QIODevice。下面我們先分別看一個使用QDataStream進(jìn)行二進(jìn)制數(shù)據(jù)讀寫的例子。

write binary data to a stream:

  QFile file("file.dat");
  file.open(QIODevice::WriteOnly);
  QDataStream out(&file);   // we will serialize the data into the file
  out << QString("the answer is");   // serialize a string
  out << (qint32)42;        // serialize an integer

read binary data from a stream:

  QFile file("file.dat");
  file.open(QIODevice::ReadOnly);
  QDataStream in(&file);    // read the data serialized from the file
  QString str;
  qint32 a;
  in >> str >> a;           // extract "the answer is" and 42

每一項被寫入的數(shù)據(jù),都是按一種預(yù)定義的二進(jìn)制格式寫入的,改格式取決于具體每一項的類型。而QDataStream支持的類型包括QBrush,QColor,QDateTime等等。

特別注意,對應(yīng)整數(shù)來說,在寫入時最好轉(zhuǎn)換成Qt中的某種整數(shù)類型,讀取時也讀取為同樣的Qt整數(shù)類型。這可以確保得到正確大小的整數(shù)并且可以屏蔽掉不同編譯器和平臺之間的差異。舉個栗子,對于一個char* 字符串來說,先寫入一個32-bit的整數(shù)值,該值就是字符串的長度,包括'\0',緊接著是字符串中 的每一個字符,包括'\0'。當(dāng)讀取時,也是這樣操作,寫讀取4字節(jié)創(chuàng)建出一個32-bit的字符串長度值,然后再根據(jù)創(chuàng)建出的長度值讀取出相應(yīng)個數(shù)的字符,包括'\0'。

版本

QDataStream的二進(jìn)制格式從Qt1.0就開始形成了,很有可能在將來繼續(xù)進(jìn)化已反應(yīng)Qt的變化。當(dāng)操作復(fù)雜數(shù)據(jù)類型時,我們就要確保讀取和寫入時的QDataStream版本是一樣的。如果你需要向前和向后兼容,可以在代碼中使用硬編碼指定流的版本號:

stream.setVersion(QDataStream::Qt_4_0);

如果你正在創(chuàng)建一種新的二進(jìn)制數(shù)據(jù)格式,比如作為你的應(yīng)用程序創(chuàng)建的文件的格式,你可以使用QDataStream以一種可移植的格式去寫入這些數(shù)據(jù)。典型情況下,你可能會在文件頭寫入一個簡短的幻數(shù)字符串和一個版本數(shù)字,來用于將來擴(kuò)展。例如:

  QFile file("file.xxx");
  file.open(QIODevice::WriteOnly);
  QDataStream out(&file);
 
  // Write a header with a "magic number" and a version
  out << (quint32)0xA0B0C0D0;
  out << (qint32)123;
 
  out.setVersion(QDataStream::Qt_4_0);
 
  // Write the data
  out << lots_of_interesting_data;

那么,我們就可以以下面這種方式來讀取:

  QFile file("file.xxx");
  file.open(QIODevice::ReadOnly);
  QDataStream in(&file);
 
  // Read and check the header
  quint32 magic;
  in >> magic;
  if (magic != 0xA0B0C0D0)
      return XXX_BAD_FILE_FORMAT;
 
  // Read the version
  qint32 version;
  in >> version;
  if (version < 100)
      return XXX_BAD_FILE_TOO_OLD;
  if (version > 123)
      return XXX_BAD_FILE_TOO_NEW;
 
  if (version <= 110)
      in.setVersion(QDataStream::Qt_3_2);
  else
      in.setVersion(QDataStream::Qt_4_0);
 
  // Read the data
  in >> lots_of_interesting_data;
  if (version >= 120)
      in >> data_new_in_XXX_version_1_2;
  in >> other_interesting_data;

同時,還可以在序列化數(shù)據(jù)時指定一個字節(jié)序。默認(rèn)情況下是big endian。除非特殊需求,我們一個建議保持這個設(shè)置的默認(rèn)值,不做修改。

讀寫原生二進(jìn)制數(shù)據(jù)

有時,我們希望直接從data stream里讀取原生的二進(jìn)制數(shù)據(jù)。此時,可以使用readRawData() 將數(shù)據(jù)讀入一個預(yù)先分配好的char*;同樣的數(shù)據(jù)也可以使用writeRawData() 函數(shù)寫入data stream。但要記住,使用這種方式的話,要由你自己進(jìn)行所有數(shù)據(jù)的編碼和解碼。于此類似的另外兩個函數(shù)是readBytes() 和 writeBytes()。這兩個函數(shù)與上面的Raw版本相比,區(qū)別主要是:readBytes() 先讀取一個quint32值,該值被當(dāng)做將要讀取的數(shù)據(jù)的長度,然后讀取相應(yīng)字節(jié)的數(shù)據(jù)到預(yù)先定義好的char*中;writeBytes() 也同理,先寫入一個quint32的數(shù)據(jù)長度值,緊接著寫入相應(yīng)數(shù)據(jù)。同樣,使用這兩個函數(shù),所以數(shù)據(jù)的編碼和解碼要有我們自己負(fù)責(zé)。注意,readBytes() 不需要我們事先分配好內(nèi)存, 而readRawData() 需要我們事先分配好內(nèi)存。

讀寫Qt集合類和其他Qt類

Qt的常見集合類也可以使用QDataStream進(jìn)行序列化,這包括QList,QLinkedList,QVector,QSet,QHash和QMap。不過,序列化這些類的流操作符不是這個類的成員函數(shù)而已。同理,讀寫Qt中的其他類型,比如QImage,也是可以的。

使用事務(wù)

當(dāng)在一個異步的設(shè)備上讀取數(shù)據(jù)時,數(shù)據(jù)塊可以在任意的時間點(diǎn)上到來。所以,為了應(yīng)對這種情況,QDataStream提供了一個事務(wù)機(jī)制來確保原子性的完成一系列的流操作符。例如,你可以在操作socket時,在相應(yīng)readyRead() 的槽函數(shù)中,使用事務(wù)來完成不完整的數(shù)據(jù)讀取。

  in.startTransaction();
  QString str;
  qint32 a;
  in >> str >> a; // try to read packet atomically
 
  if (!in.commitTransaction())
      return;     // wait for more data

如果沒有完整的數(shù)據(jù)包到來,commitTransaction() 會返回false,并將stream重置為初始狀態(tài),然后,等待更多數(shù)據(jù)的到來。

下面給出一個簡單的測試程序:

#include <QCoreApplication>
#include <QDebug>
#include <QDataStream>
#include <QFile>
#include <QVector>
#include <QMap>
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
 
    //write
    QFile file("test.dat");
    if (!file.open(QIODevice::ReadWrite))
    {
        qDebug() << "open file failed";
        return 0;
    }
    QDataStream ds(&file);
    const char *wstr = "hello-world";
    quint32 wi = 1234;
    double wd = 1.1;
    float wf = 2.2f;
    QVector<int> wvector;
    wvector.push_back(1);
    wvector.push_back(2);
    wvector.push_back(3);
    QMap<int,int> wmap;
    wmap.insert(4, 4);
    wmap.insert(5, 5);
    wmap.insert(6, 6);
    ds << wstr;
    ds << wi;
    ds << wd;
    ds << wf;
    ds << wvector;
    ds << wmap;
    ds.writeBytes("file end ", qstrlen("file end "));
    ds.writeRawData("really end", qstrlen("really end"));
 
    //read
    file.seek(0);
    char *rstr;
    quint32 ri;
    double rd;
    float rf;
    QVector<int> rvector;
    QMap<int, int> rmap;
    char *rbytes;
    uint len;
    char *rraw = new char[100]{0};
    int rlen;
    ds >> rstr;
    ds >> ri;
    ds >> rd;
    ds >> rf;
    ds >> rvector;
    ds >> rmap;
    ds.readBytes(rbytes, len);
    ds.readRawData(rraw, rlen);
    qDebug() << rstr;
    qDebug() << ri;
    qDebug() << rd;
    qDebug() << rf;
    qDebug() << rvector;
    qDebug() << rmap;
    qDebug() << rbytes;
    qDebug() << rraw;
 
    return a.exec();
}

到此這篇關(guān)于QT中QDataStream二進(jìn)制數(shù)據(jù)讀寫的實現(xiàn)的文章就介紹到這了,更多相關(guān)QT QDataStream二進(jìn)制數(shù)據(jù)讀寫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言的strcpy函數(shù)你了解嗎

    C語言的strcpy函數(shù)你了解嗎

    這篇文章主要為大家詳細(xì)介紹了C語言的strcpy函數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • C++學(xué)習(xí)之函數(shù)模板的使用詳解

    C++學(xué)習(xí)之函數(shù)模板的使用詳解

    函數(shù)模板可以適用泛型來定義函數(shù),其中泛型可以是(int, double, float)等替換。這篇文章主要來和大家聊聊函數(shù)模板的具體使用,感興趣的可以了解一下
    2023-03-03
  • 常用的C++標(biāo)準(zhǔn)庫頭文件小結(jié)

    常用的C++標(biāo)準(zhǔn)庫頭文件小結(jié)

    C++標(biāo)準(zhǔn)庫定義了一系列函數(shù)、宏和對象,以實現(xiàn)跨團(tuán)隊、跨平臺的高效且具有卓越性能的標(biāo)準(zhǔn)化 C++ 代碼, 本文介紹常用的C++標(biāo)準(zhǔn)庫頭文件,需要的朋友可以參考下
    2023-11-11
  • matlab?GUI指紋識別門禁系統(tǒng)介紹及源碼實現(xiàn)

    matlab?GUI指紋識別門禁系統(tǒng)介紹及源碼實現(xiàn)

    這篇文章主要為大家介紹了matlab?GUI指紋識別門禁系統(tǒng)的介紹及源碼實現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-02-02
  • C++結(jié)構(gòu)體數(shù)組詳細(xì)解析

    C++結(jié)構(gòu)體數(shù)組詳細(xì)解析

    定義結(jié)構(gòu)體數(shù)組和定義結(jié)構(gòu)體變量類似,定義結(jié)構(gòu)體數(shù)組時只需聲明其為數(shù)組即可
    2013-10-10
  • C++類的返回值是*this的成員函數(shù)問題

    C++類的返回值是*this的成員函數(shù)問題

    這篇文章主要介紹了C++類的返回值是*this的成員函數(shù)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C++變量和基本類型詳解

    C++變量和基本類型詳解

    這篇文章主要介紹了C++變量和基本類型,,一定要注意局部變量與全局變量的作用范圍,需要的朋友可以參考下,希望能夠給你帶來幫助
    2021-10-10
  • Dev C++編譯時運(yùn)行報錯source file not compile問題

    Dev C++編譯時運(yùn)行報錯source file not compile問題

    這篇文章主要介紹了Dev C++編譯時運(yùn)行報錯source file not compile問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Qt實現(xiàn)字符串生成二維碼功能

    Qt實現(xiàn)字符串生成二維碼功能

    這篇文章主要介紹了如何利用Qt實現(xiàn)字符串生成二維碼功能,文中的實現(xiàn)過程講解詳細(xì),對我們學(xué)習(xí)Qt有一定的幫助,需要的可以參考一下
    2022-01-01
  • C語言數(shù)組的各種操作梳理

    C語言數(shù)組的各種操作梳理

    數(shù)組是一組有序的數(shù)據(jù)的集合,數(shù)組中元素類型相同,由數(shù)組名和下標(biāo)唯一地確定,數(shù)組中數(shù)據(jù)不僅數(shù)據(jù)類型相同,而且在計算機(jī)內(nèi)存里連續(xù)存放,地址編號最低的存儲單元存放數(shù)組的起始元素,地址編號最高的存儲單元存放數(shù)組的最后一個元素
    2022-04-04

最新評論