qt文件處理

Qt提供了QFile類來進行文件處理,爲了更方便地處理文本文件或二進制文件,Qt還提了QTextStream類和QDataStream類,處理臨時文件可以使用QTemporaryFile,獲取文件信息可以使用QFileInfo
,
處理目錄可以使用QDir.監視文件和目錄變化可以使用QFileSystemWatcher.

讀寫文本文件
QFile
類提供了讀寫文件的接口,QFile類可以讀寫文本文件,二進制文件和Qt資源文件,也可以使用更方便的QTextStream,QDataStream類讀取文本文件和二進制文件,要打開一個文件,可以在構造函數中指定文件名,也可以在任何時候使用setFileName()函數設置文件名,打開文件使用open函數,關閉文件使用close函數。QFile中可以使用QIODevice中繼承的readLine()函數讀寫文本文件的一行。如:
  QFile file("zeki.txt");
  if(file.open(QIODevice::ReadOnly))
  {
      char buffer[2048];
      qint 64 lineLen=file.readLine(buffer,sizeof(buffer));
      if(lineLen!=-1)
      {
         qDebug<       }
  }
如果讀取成功,readLine返回實際讀取的字節數,如果讀取失敗則返回-1
QTextStream
提供了更爲方便的接口來讀寫文本,QTextStream可以操作QIODevice,QByteArray,QString.QTextStream使用流操作符,可以方便地讀寫單詞,行和數字。爲了產生文本,QTextStream提供了填充,對齊和數字格式化的格式選項。如
   QFile data("test.txt");
   if(data.open(QFile::WriteOnly|QFile::Truncate))
   {
        QTextStream out(&data);
        out<    }
   
QTextStream
的格式化函數
----------------------------------------------
qSetFieldWidth(int width)  
設置字段寬度
qSetPadChar(QChar ch)      
設置填充字符
qSetRealNumberPrecision(int precision) 
設置實數精度
----------------------------------------------
QTextStream中使用的默認編碼是QTextCodec::codecForLocal()函數返回的編碼,同時能夠自動檢測Unicode。也可以使用QTextStream::setCodec(QTextCodec *codec)函數設置的流編碼。

操作二進制文件
QDataStream
類提供了將二進制文件串行化的功能,QDataStream實現了c++基本數據類型的串行化,如char,short,int char*更復雜的數據類型串行化通過將數據類型分解爲基本的數據類型來完成。下面用來寫二進制數據到數據流。
QFile file("binary.dat");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
out< out<<(qint32)42<<(qint32)96;
將上面寫入的文件讀入的過程爲:
QFile file("binary.dat");
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
QString str;
qint32 x,y;
in>>str>>x>>y;
每一個條目都可以定義的二進制格式寫入文件,Qt中的很多類型,包括QBrush,QColor,QDateTime,QFont,QPixmap,QString,QVariant等都可以寫入數據流。

如果需要讀取原始數據,可以使用readRawData()讀取數據到預先定義好的char *緩衝區,寫原始數據使用writeData(),讀寫原始數據需要對數據進行編碼和解碼。
下面例子演示了使用QDataStream進行讀寫文件的過程。
#include
#include
using namespace std;
int main(int argc,char **argv)
{
   QCoreApplication app(argc,argv);
   QFile file("binary.file");
   file.open(QIODevice::WriteOnly|QIODevice::Truncate);
   QDataStream out(&file);
   out<    out<    out<<(qint32)21;
   file.close();
   
   file.setFileName("binary.file");
   if(!ifle.open(QIODevice::ReadOnly))
   {
      cout<<"
打開文件錯誤!";
      return 1;
   }
   QDataStream in(&file);
   QString name;
   QDate birthday;
   qint32 age;
   in>>name>>birthday>>age;
      qDebug()<       cout<       qPrintable(birthday.toString("yyyy MMMM dd dddd"));
   file.close();
   return 0;
}
在例子中,QDataStream類寫入了姓名(QString),生日(QDate),和年齡(qint32)三個數據,讀取時使用相同的類型讀出。QDataStream可以讀取任意以QIODevice爲基類生成的對象產生的數據。如QTcpSocket,QUdpSocket,QBuffer,QFile,QProcess等類的數據。可以使用QDataStreamQAbstractSocket一端寫入數據,另一端使用QDataStream讀取數據,這樣就免去了繁瑣的
高低端字節轉換過程。
臨時文件
實際應用中有時可能需要使用臨時文件,Qt中提供QTemporaryFile類來提供臨時文件。QTemporayFile可以安全地創建一個第一無二的臨時文件。臨時文件通過open()來創建。Qt可以保證臨時文件不會重複。在臨時文件對象銷燬後,將自動刪除該臨時文件。臨時文件通過close()關閉後還可以打開,只要臨時文件對象還沒有銷燬,臨時文件就一直存在並由QTemporaryFile內部保持打開。系統的臨時目錄可以通過QDir::tempPath()來獲取,unix/linux系統上的臨時目錄通常時/tempwindows上通常是TEM/TMP指定

 

 

2.目錄操作和文件管理
QDir
類具有存取目錄結構和內容的能力。使用QDir可以操作目錄,存取目錄或文件信息,操作底層文件系統,而且還可以存取Qt的資源文件。Qt使用/作爲通用的目錄分割符和URL路徑分隔符。Qt可以使用相對路徑和絕對路徑指向一個文件,isRelative()isAbsolute()函數可以判斷QDir對象使用的是相對路徑還是絕對路徑。將相對路徑轉換爲絕對路徑使用makeAbsolute()函數。目錄路徑可以通過path()函數返回,通過setPath()函數設置新路徑,絕對路徑使用absolutePath()返回。目錄名可以使用dirName()返回。目錄的路徑可以通過cd() cdUp()改變,可以使用mkdir()創建目錄,rename()改變目錄名。判斷目錄是否存在可以使用exists(),目錄的屬性可以使用isReadable(),isAbsolute(),isRelative()isRoot()來獲取,目錄下有很多條目,包括文件,目錄和符號鏈接,總的條目數可以使用count()來統計。entryList()可以返回目錄下所有條目組成的字符串鏈表,文件可以使用remove()函數刪除,rmdir()刪除目錄。
linux du
命令

int main(int argc, char **argv)
{
   QCoreApplication app(argc,argv);
   QStringList args=app.arguments();
   QString path;
   if(args.count()>1)
     path=args[1];
   else
     path=QDir::currentPath();
   qDebug()<    du(path);
   return 0;
}
qint64 du(const QString &path)
{
    QDir dir(path);
    qint64 size=0;
    foreach(QFileInfo fileInfo,dir.entryInfoList(QDir::Files))
       size+=fileInfo.size();
    foreach(QString subDir,dir.entryList(QDir::Dirs|QDir::NoDotAndDotDot))
       size+=du(path+Dir::separator()+subDir);
    char unit=\\\'B\\\';
    if(curSize>1024)
    {
       curSize/=1024;
       unit=\\\'K\\\';
       if(curSize>1024)
       {
          curSize/=1024;
          unit=\\\'M\\\';
          if(curSize>1024)
          {
            curSize/=1024;
            unit=\\\'G\\\';
          }
        }
     }
     cout<      return size;
}
函數du()中,entryInfoList(QDir::Files)函數返回文件信息,然後根據這些信息計算文件大小,接下來判斷是否有子目錄,如果有則遞歸計算。dir.etnryList(QDir::Dirs|QDir::NoDotAndDotDot)返回所有子目錄並過濾掉. .. 目錄。由於windows(),linux平臺/ \差異,使用QDir::separator()函數來返回特定平臺的目錄分隔符。另外QDirIterator可以完成
枚舉目錄的功能,Qt4.3還引入了文件搜索前綴的概念,文件搜索前綴時至少由兩個字符組成,用來搜索指定文件的路徑。
QDir::setSearchPaths("docs",QStringList("c:\My Docments"));
QDir::addSearchPaht("Docs",QStringList("D:|Documents"));
QFile file("docs::qt4.doc");
這樣就可以在兩個目錄中查找。

文件管理
QFileInfo
類提供了與系統無關的文件信心,它能提供文明名和路徑,存取權限,以及文件是否爲目錄或符號鏈接,文件大小,以及最後修改/讀取的時間等。QFileInfo也能從資源中獲取信息。QFileInfo可以使用相對路徑或絕對路徑。文件名可以在QFileInfo的構造函數中傳遞,也可以使用setFile()函數指定,要判斷一個函數是否存在,使用exits()函數,文件大小可以通過size()函數獲取,文件類型可以通過isFile()isDir(),isSymLink()來獲取,symLinkTarget()函數返回符號鏈接所指向的真正文件名。QFileInfo提供refresh函數刷新文件信息,如果需要QFileInfo每次從文件系統讀取信息,二不是從緩存讀取,可以使用setCaching(false)關閉緩存。文件名和目錄可以通過path()fileName()分解,fileName()返回的部分可以通過baseName()extension()來獲得主文件名和擴展文件名,文件的操作日期可以通過created(),lastModified()lastRead()獲取,文件的存取權限可通國isReadable,isWriteable(),isExcutetable()獲取,文件的屬主可以通過owner(),ownerId,group(),groupId()獲取,文件的權限和屬主也可以通過permission()一起讀取。

監視文件系統的變化
Qt中可以使用QFileSystemWatcher類來監視文件和目錄的改變.使用addPath()函數來監視指定的文件和目錄,如果需要監視多個目錄,使用addPaths()來加入監視,如果要一處不需要監視的目錄,可以使用removePath(),removePaths()函數.當監視的文件被修改或刪除時,產生一個fileChanged()信號,如果被監視的目錄被修改或刪除,產生directoryChanged()信號,下例實現了監視指定目錄的功能.
#include
#include
#include
#Include"Msg.h"
using namespace std;
int main(int argc,char **argv)
{
    QApplication app(argc,argv);
    QTextCodec::setCodecForTr(QTextCodec::codecForLocale())
    
    Msg msg;
    msg.show();
    return app.exec();
}
Msg::Msg()
{
   QFont font;
   font.setPointSize(24);
   setFont(font);
   QStringList args=qApp->arguments();
   QString path;
   if(args.count()>1)
     path=args[1];
   else
     path=QDir::currentPath();
   label=new QLabel();
   label->setText(tr("
監視的目錄:")+path);
   
   QVBoxLayout *layout=new QVBoxLayout;
   layout->addWidget(label);
   setLayout(layout);
   
   fsWatcher.addPath(path);
   connect(&fsWatcher,SIGNAL(directoryChanged(QString)),this,SLOT(directoryChanged(QString)));
}
在構造函數中讀取命令指定的目錄作爲監視目錄,如果沒有指定則監視當前目錄,使用connect()函數將目錄的directroyChanged()信號和響應函數連接.
void Msg::directoryChanged(QString path)
{
    QMessageBox::information(NULL,tr("
目錄變化"),path);
}

文件引擎
Qt
QtDir,QFile,QFileInfo類在內部都使用一個類,QAbstractFileEngine.通過繼承QAbstractFileEngine,可以編寫自己的文件處理函數,然後繼承QAbstractFileEngineHander類註冊自己的文件引擎,然後這樣就可以使用自己的文件讀取引擎了.QAbstractFileEngineHandler是創建QAbstractFileEngine的類工廠.當打開一個文件時,Qt通過內部註冊的文件引擎鏈表,選擇合適的文件引擎並創建相應的引擎對象.爲了安裝一個特定的文件引擎,必須繼承QAbstractFileEngineHandler並實現create()函數.實例化引擎時Qt自動註冊該引擎,最後註冊的引擎比之前註冊的優先級高.
如果想讀取tar文件的引擎,可以從QAbstractFileEngineHandler類繼承
class TarEngineHandler:public QAbstractFileEngineHandler
{
    public:
        QAbstractFileEngine *create(const QString &fileName) const;
};
create()
函數返回TarEngine對象,TarEngine是文件引擎,時真正的文件處理類.
QAbstractFileEngine *TarEngineHandler::create(const QString &fileName) const
{
    return fileName.toLower().endsWith(".tar")?new TarEngine(fileName):0;
}

 

我們使用自定義的二進制格式來實現Spreadsheet文件的保存和讀取。我們用QFile和QDataStream這兩個類來實現,它們一起提供了平臺無關的二進制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;
}
函數writeFile()由MainWindow::saveFile()調用,把文件保存到磁盤上。如果保存成功返回true,否則返回false。
首先我們使用給定的程序名創建一個QFile對象,調open()打開這個文件準備寫入。同時創建一個QDataSteam對象來操作QFile對象,將數據寫入文件中。
在寫數據之前,我們將程序的光標換成等待形式,數據寫完後恢復原來的鼠標形狀。函數結束時,QFile的析構函數把文件自動關閉。
QDataStream支持基本的C++類型,也支持多種Qt類型。語法和標準C++<iostream>類是一樣的。例如:
Out<<x<<y<<z;把變量x,y,z寫入數據流。
In>>x>>y>>z; 從數據流中讀取數據到x,y,z中。在不同的平臺上,基本的C++類型如short,char,int,long,long long會有不同的字長。最好把它們轉換爲qint8,quint8,qint16,quint16,qint32,quint32,qint64,quint64,這些類型能確保字長是不隨平臺改變的。
Spreadsheet程序的文件格式非常簡單。一個Spreadsheet文件開頭部分是一個32位的標識數字(MagciNumber,在spreadsheet.h中定義的,一個二進制的隨機數),這個數字後面是一系列的數據塊,包括一個單元格的行號,列號和公式組成。爲了節省空間,不保存空的單元格。
 
數據類型的二進制表示由類QDataStream決定。如:quint16表示按big-endian順序保存爲兩個字節。一個QString類型表示是字符串的長度後面接着Unicode碼組成。
自Qt1.0以來,Qt數據類型的二進制表示有了很大變化。在未來的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;
}
 
函數readFile()和writeFile()很相似。這次文件的打開方式爲QIODevice::ReadOnly而不是QIODevice::writeOnly。設置QDataStream的版本爲7。寫文件和讀文件的版本必須一致。
如果文件的magic number號是正確的,調用clear()清空所有的表格,因爲文件中只是保存了非空的單元格數據,不能保證所有的單元格都會被設置,所以必須確保再讀取單元格數據前所有的表格要清空。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章