程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Qt學習之路(56): 二進制文件讀寫

Qt學習之路(56): 二進制文件讀寫

編輯:關於C語言

今天開始進入 Qt 的另一個部分:文件讀寫,也就是 IO。文件讀寫在很多應用程序中都是需要的。Qt 通過 QIODevice 提供了IO的抽象,這種設備(device)具有讀寫字節塊的能力。常用的IO讀寫的類包括以下幾個: QFlie 訪問本地文件系統或者嵌入資源 QTemporaryFile 創建和訪問本地文件系統的臨時文件 QBuffer 讀寫 QByteArray QProcess 運行外部程序,處理進程間通訊 QTcpSocket TCP 協議網絡數據傳輸 QUdpSocket 傳輸 UDP 報文 QSslSocket 使用 SSL/TLS 傳輸數據  QProcess、QTcpSocket、QUdpSoctet 和 QSslSocket 是順序訪問設備,它們的數據只能訪問一遍,也就是說,你只能從第一個字節開始訪問,直到最後一個字節。QFile、QTemporaryFile 和 QBuffer 是隨機訪問設備,你可以從任何位置訪問任意次數,還可以使用 QIODevice::seek() 函數來重新定位文件指針。 在訪問方式上,Qt 提供了兩個更高級別的抽象:使用 QDataStream 進行二進制方式的訪問和使用 QTextStream 進行文本方式的訪問。這些類可以幫助我們控制字節順序和文本編碼,使程序員從這種問題中解脫出來。 QFile 對於訪問獨立的文件是非常方便的,無論是在文件系統中還是在應用程序的資源文件中。Qt 同樣也提供了 QDir 和 QFileInfo 兩個類,用於處理文件夾相關事務以及查看文件信息等。 這次我們先從二進制文件的讀寫說起。 以二進制格式訪問數據的最簡單的方式是實例化一個 QFile 對象,打開文件,然後使用 QDataStream 進行訪問。QDataStream 提供了平台獨立的訪問數據格式的方法,這些數據格式包括標准的 C++ 類型,如 int、double等;多種 Qt 類型,如QByteArray、QFont、QImage、QPixmap、QString 和 QVariant,以及 Qt 的容器類,如 QList<T> 和 QMap<K, T>。先看如下的代碼:

  1. QImage image("philip.png");  
  2.  
  3. QMap<QString, QColor> map;  
  4. map.insert("red", Qt::red);  
  5. map.insert("green", Qt::green);  
  6. map.insert("blue", Qt::blue);  
  7.  
  8. QFile file("facts.dat");  
  9. if (!file.open(QIODevice::WriteOnly)) {  
  10.     std::cerr << "Cannot open file for writing: " 
  11.               << qPrintable(file.errorString()) << std::endl;  
  12.     return;  
  13. }  
  14.  
  15. QDataStream out(&file);  
  16. out.setVersion(QDataStream::Qt_4_3);  
  17.  
  18. out << quint32(0x12345678) << image << map; 
這裡,我們首先創建了一個 QImage 對象,一個 QMap<QString, QColor>,然後使用 QFile 創建了一個名為 "facts.dat" 的文件,然後以只寫方式打開。如果打開失敗,直接 return;否則我們使用 QFile 的指針創建一個 QDataStream 對象,然後設置 version,這個我們以後再詳細說明,最後就像 std 的 cout 一樣,使用 << 運算符輸出結果。 0x12345678 成為“魔術數字”,這是二進制文件輸出中經常使用的一種技術。我們定義的二進制格式通常具有一個這樣的“魔術數字”,用於標志文件格式。例如,我們在文件最開始寫入 0x12345678,在讀取的時候首先檢查這個數字是不是 0x12345678,如果不是的話,這就不是可識別格式,因此根本不需要去讀取。一般二進制格式都會有這麼一個魔術數字,例如 Java 的 class 文件的魔術數字就是 0xCAFE BABE(很 Java 的名字),使用二進制查看器就可以查看。魔術數字是一個 32 位的無符號整數,因此我們使用 quint32 宏來得到一個平台無關的 32 位無符號整數。 在這段代碼中我們使用了一個 qPrintable() 宏,這個宏實際上是把 QString 對象轉換成 const char *。注意到我們使用的是 C++ 標准錯誤輸出 cerr,因此必須使用這個轉換。當然,QString::toStdString() 函數也能夠完成同樣的操作。 讀取的過程就很簡單了,需要注意的是讀取必須同寫入的過程一一對應,即第一個寫入 quint32 型的魔術數字,那麼第一個讀出的也必須是一個 quint32 格式的數據,如
  1. quint32 n;  
  2. QImage image;  
  3. QMap<QString, QColor> map;  
  4.  
  5. QFile file("facts.dat");  
  6. if (!file.open(QIODevice::ReadOnly)) {  
  7.     std::cerr << "Cannot open file for reading: " 
  8.               << qPrintable(file.errorString()) << std::endl;  
  9.     return;  
  10. }  
  11.  
  12. QDataStream in(&file);  
  13. in.setVersion(QDataStream::Qt_4_3);  
  14.  
  15. in >> n >> image >> map; 
好了,數據讀出了,拿著到處去用吧! 這個 version 是干什麼用的呢?對於二進制的讀寫,隨著 Qt 的版本升級,可能相同的內容有了不同的讀寫方式,比如可能由大端寫入變成了小端寫入等,這樣的話舊版本 Qt 寫入的內容就不能正確的讀出,因此需要設定一個版本號。比如這裡我們使用 QDataStream::Qt_4_3,意思是,我們使用 Qt 4.3 的方式寫入數據。實際上,現在的最高版本號已經是 QDataStream::Qt_4_6。如果這麼寫,就是說,4.3 版本之前的 Qt 是不能保證正確讀寫文件內容的。那麼,問題就來了:我們以硬編碼的方式寫入這個 version,豈不是不能使用最新版的 Qt 的讀寫了? 解決方法之一是,我們不僅僅寫入一個魔術數字,同時寫入這個文件的版本。例如:
  1. QFile file("file.xxx");  
  2. file.open(QIODevice::WriteOnly);  
  3. QDataStream out(&file);  
  4.  
  5. // Write a header with a "magic number" and a version  
  6. out << (quint32)0xA0B0C0D0;  
  7. out << (qint32)123;  
  8.  
  9. out.setVersion(QDataStream::Qt_4_0);  
  10.  
  11. // Write the data  
  12. out << lots_of_interesting_data; 
這個 file.xxx 文件的版本號是 123。我們認為,如果版本號是123的話,則可以使用 Qt_4_0 版本讀取。所以我們的讀取代碼就需要判斷一下:
  1. QFile file("file.xxx");  
  2.  file.open(QIODevice::ReadOnly);  
  3.  QDataStream in(&file);  
  4.  
  5.  // Read and check the header  
  6.  quint32 magic;  
  7.  in >> magic;  
  8.  if (magic != 0xA0B0C0D0)  
  9.      return XXX_BAD_FILE_FORMAT;  
  10.  
  11.  // Read the version  
  12.  qint32 version;  
  13.  in >> version;  
  14.  if (version < 100)  
  15.      return XXX_BAD_FILE_TOO_OLD;  
  16.  if (version > 123)  
  17.      return XXX_BAD_FILE_TOO_NEW;  
  18.  
  19.  if (version <= 110)  
  20.      in.setVersion(QDataStream::Qt_3_2);  
  21.  else 
  22.      in.setVersion(QDataStream::Qt_4_0);  
  23.  
  24.  // Read the data  
  25.  in >> lots_of_interesting_data;  
  26.  if (version >= 120)  
  27.      in >> data_new_in_XXX_version_1_2;  
  28.  in >> other_interesting_data; 
這樣,我們就可以比較完美的處理二進制格式的數據讀寫了。

本文出自 “豆子空間” 博客,請務必保留此出處http://devbean.blog.51cto.com/448512/293892

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved