一、輸入輸出設備
QIODevice類是Qt中所有I/O設備的基礎接口類,為諸如QFile、QBuffer和 QTcpSocket等支持讀/寫數據塊的設備提供了一個抽象接口。QIODevice類是抽象的,無法被實例化,一般是使用它所定義的接口來提供設備無關的I/O功能。
QIODevice類的繼承關系圖
QIODevice會區別兩種類型的設備:隨機存取設備和順序存儲設備。(可以在程序中使用isSequentiaU)函數來判斷設備的類型。)
- 隨機存取設備支持使用seek()函數來定位到任意的位置。文件中的當前位置可以使用pos()函數來獲取。這樣的設備有QFile、QBuffer等。
- 順序存儲設備不支持定位到任意的位置,數據必須一次性讀取。Pos()和size() 等函數無法在操作順序設備時使用。這樣的設備有QTcpSocket、QUdpSocket 和QProcess等。
文件打開模式
訪問一個設備以前,需要使用open()函數打開該設備,而且必須指定正確的打開模式。QIODevice中所有的打開模式由QIODevice::OPenMode枚舉變量定義,其取值如下表所列,其中的一些值可以使用按位或符號“丨”來同時使用。打開設備后可以使用write()或者putChar()來進行寫人,使用read()、readLine()或者readAll()進行讀取,最后使用close()關閉設備。
枚舉值 | 描述 |
---|---|
QIODevice::NotOpen | 未打開 |
QIODevice::ReadOnly | 以只讀方式打開 |
QIODevice::WriteOnly | 以只寫方式打開 |
QIODevice::ReadWrite | 以讀寫方式打開 |
QIODevice::Append | 以追加的方式打開,新增加的內容將被追加到文件末尾 |
QIODevice::Truncate | 以重寫的方式打開,在寫入新的數據時會將游標設置在文件開頭 |
QIODevice::Text | 在讀取時,將行結束符轉換成 \n;在寫入時,將行結束符轉換成本地格式,例如 Win32 平台上是 \r\n |
QIODevice::Unbuffered | 忽略緩存 |
二、文件 QFile
QFile類提供了一個用於讀/寫文件的接口,它是一個可以用來讀/寫文本文件、二進制文件和Qt資源的I/O設備。QFile可以單獨使用,也可以和QTextStream或者QDataStream—起使用,這樣會更方便。
一般在構建QFile對象時便指定文件名,當然也可以使用setFileName()在其他任何時間進行設置。可以使用exists()來檢査文件是否存在,remove()來刪除一個文件。更多與文件系統相關的高級操作在QFilelnfo和QDir類中提供。
一個文件可以使用open()打開,使用close()關閉,使用flush()刷新。文件的數據讀寫一般使用QTextStream或者QDataStream來完成,不過也可以使用繼承自QIODevice類的一些函數,比如read()、readLine()、readAll()和write(),還有一次只操作一個字符的getChar()、putChar()和ungetChar()等函數。可以使用size()函數來獲取文件的大小,使用seek()來定位到文件的任意位置,使用pos()來獲取當前的位置,使用atEnd()來判斷是否到達了文件的末尾。
(1)直接使用QFile讀寫文件
示例程序如下:
//直接使用QFile寫文件
QFile fileW("test.txt");
if (!fileW.open(QIODevice::WriteOnly | QIODevice::Text))
return;
fileW.write("first line!\nsecond line");
fileW.close();
//直接使用QFile讀文件
QFile fileR("test.txt");
if (!fileR.open(QIODevice::ReadOnly | QIODevice::Text))
return;
while (!fileR.atEnd())
{
QByteArray line = fileR.readLine();
qDebug() <<line;
}
fileR.close();
(2)使用文本流讀/寫文本文件
QTextStream類提供了一個方便的接口來讀/寫文本,可以在QIODevice、QByteArray和QString上進行操作。使用QTextStream的流操作符,可以方便地讀/寫單詞、行和數字。示例程序如下:
//使用QTextStream文本流讀文件
QFile fileW("test.txt");
if (!fileW.open(QIODevice::WriteOnly | QIODevice::Text))
return -1;
QTextStream out(&fileW);
out << "first line" << "\nsecond line";
fileW.close();
//使用QTextStream文本流寫文件
QFile fileR("test.txt");
if (!fileR.open(QIODevice::ReadOnly | QIODevice::Text))
return -1;
QTextStream in(&fileR);
while (!in.atEnd())
{
QString line = in.readLine();
qDebug() <<line;
}
可以使用seek()來定位到一個指定位置,使用atEnd()判斷是否還有可以讀取的數據。如果調用了flush()函數,QTextStream會清空寫緩沖中的所有數據,並且調用設備的flush()函數。
在內部,QTextStream使用了一個基於Unicode的緩沖區,QTextStream使用QTextCodec來自動支持不同的字符集。默認的,使用QTextCodec ::codecForLocale()返回的編碼來進行讀寫,也可以使用setCodec()函數來設置編碼。
(3)使用數據流讀/寫二進制數據
QDataStream類實現了將QIODevice的二進制數據串行化。一個數據流就是一個二進制編碼信息流,完全獨立於主機的操作系統、CPU和字節順序。數據流也可以讀/寫未編碼的原始二進制數據。QDataStream類可以實現C+ +基本數據類型的串行化,比如char、Sh〇rt、im和char*等。而串行化更復雜的數據,是通過將數據分解為基本的數據類型來完成的。示例程序如下:
//使用QTextStream文本流讀文件
QFile fileW("test.txt");
if (!fileW.open(QIODevice::WriteOnly))
return -1;
QDataStream out(&fileW);
//串行化字符串(寫入時,要求強制轉換為QString類型,否則寫入的是亂碼)
out << QString("the answer is");
//串行化整數
out << static_cast<qint32>(42);
fileW.close();
//使用QTextStream文本流寫文件
QFile fileR("test.txt");
if (!fileR.open(QIODevice::ReadOnly))
return -1;
QDataStream in(&fileR);
QString str;
qint32 num;
in >> str >> num;
qDebug() << str << num; //輸出:"the answer is" 42
fileR.close();
寫到數據流中的每一個條目都是使用一個預定義的格式寫入的,這個格式依賴於條目的類型。(否則寫入的會是亂碼)支持的 Qt 類型包括 QBrush、QColor、QDateTime、QFom、QPixmap、 QString、QVariant和很多其他格式。
三、文件信息 QFilelnfo
QFilelnfo類提供了與系統無關的文件信息,包括文件的名稱、在文件系統中的位置(路徑)、文件的訪問權限以及是否是一個目錄或者符號鏈接等 。QFilelnfo也可以獲取文件的大小和最近一次修改/讀取的時間,還可以獲取Qt資源的相關信息 。 QFilelnfo指向的文件可以在QFileinfo對象構建時設置,或者以后使用setFile()來設置。
- QFileInfo可以使用相對(relative)路徑或者絕對(absolute)路徑來指向一個文件,還可以使用makeAbsolute()來將一個相對路徑轉換為絕對路徑。
- 文件的類型可以使用isFile()、isDir()和isSymLink()來獲取。 可以分別使用path()和fileName()來獲取文件的路徑和文件名,還可以使用baseName()來獲取文件名中的基本名稱,使用suffix()來獲取文件名的后綴,使用completeSuffix()來獲取復合后綴。
- 文件的日期可以使用created()、lastModified()和lastRead()來返回;
- 訪問權限可以使用isReadable()、isWritable()和isExecutable()來獲取;
- 文件的所有權可以使用owner()、ownerId()、group()和groupId()來獲取。
新建Qt5控制台應用,名稱為myFile,創建完成后將main.cpp文件的內容更改為:
#include <QtCore/QCoreApplication>
#include <QFileInfo>
#include <QTextCodec>
#include <QStringList>
#include <QDateTime>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 以只寫方式打開,如果文件不存在,那么會創建該文件
QFile file("myfile.txt");
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
qDebug() << file.errorString();
file.write("helloQt!\nyafeilinux");
file.close();
// 獲取文件信息
QFileInfo info(file);
qDebug() << QObject::tr("絕對路徑:") << info.absoluteFilePath() << endl
<< QObject::tr("文件名:") << info.fileName() << endl
<< QObject::tr("基本名稱:") << info.baseName() << endl
<< QObject::tr("后綴:") << info.suffix() << endl
<< QObject::tr("創建時間:") << info.created() << endl
<< QObject::tr("大小:") << info.size();
// 以只讀方式打開
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
qDebug() << file.errorString();
qDebug() << QObject::tr("文件內容:") << endl << file.readAll();
qDebug() << QObject::tr("當前位置:") << file.pos();
//移動文件開始讀取位置為0
file.seek(0);
QByteArray array;
array = file.read(5);
qDebug() << QObject::tr("前5個字符:") << array
<< QObject::tr("當前位置:") << file.pos();
//移動文件開始讀取位置為15
file.seek(15);
array = file.read(5);
qDebug() << QObject::tr("第16-20個字符:") << array;
file.close();
return a.exec();
}
執行程序,控制台輸出如下:
"絕對路徑:" "D:/Project/C++/Qt/myFile/build-myFile-Desktop_Qt_5_9_7_MinGW_32bit-Debug/myfile.txt"
"文件名:" "myfile.txt"
"基本名稱:" "myfile"
"后綴:" "txt"
"創建時間:" QDateTime(2019-06-17 16:58:01.230 中國標准時間 Qt::TimeSpec(LocalTime))
"大小:" 20
"文件內容:"
"helloQt!\nyafeilinux"
"當前位置:" 20
"前5個字符:" "hello" "當前位置:" 5
"第16-20個字符:" "linux"
四、臨時文件 QTemporaryFile
QTemporaryFile類是一個用來操作臨時文件的I/O設備,它可以安全地創建一個唯一的臨時文件。當調用open()函數時便會創建一個臨時文件,臨時文件的文件名可以保證是唯一的,當銷毀QTemporaryFile對象時,該文件會被自動刪除掉。
在調用open()函數時,默認會使用QIODevice::ReadWrite模式,可以像下面的代碼這樣來使用QTemporaryFile類:
QTemporaryFile file;
if (file.open())
{
// 在這里對臨時文件進行操作,file.fileName()可以返回唯一的文件名
}
在調用了close()函數后重新打開QTemporaryFile是安全的,只要QTemporaryFile的對象沒有被銷毀,那么唯一的臨時文件就會一直存在而且由QTemporaryFile內部保持打開。臨時文件默認會生成在系統的臨時目錄里,這個目錄的路徑可以使用QDir::tempPath()來獲取。