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等類的數據。可以使用QDataStream在QAbstractSocket一端寫入數據,另一端使用QDataStream讀取數據,這樣就免去了繁瑣的
高低端字節轉換過程。
臨時文件
實際應用中有時可能需要使用臨時文件,Qt中提供QTemporaryFile類來提供臨時文件。QTemporayFile可以安全地創建一個第一無二的臨時文件。臨時文件通過open()來創建。Qt可以保證臨時文件不會重複。在臨時文件對象銷燬後,將自動刪除該臨時文件。臨時文件通過close()關閉後還可以打開,只要臨時文件對象還沒有銷燬,臨時文件就一直存在並由QTemporaryFile內部保持打開。系統的臨時目錄可以通過QDir::tempPath()來獲取,unix/linux系統上的臨時目錄通常時/temp在windows上通常是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;
}
{
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::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;
}