Qt學習筆記(三十二):Qt 中的文件讀寫操作

一、文件系統:

文件操作是應用程序必不可少的部分。Qt 作爲一個通用開發庫,提供了跨平臺的文件操作能力。Qt 通過QIODevice提供了對 I/O 設備的抽象,這些設備具有讀寫字節塊的能力。下面是 I/O 設備的類圖(Qt5):

  • QIODevice:所有 I/O 設備類的父類,提供了字節塊讀寫的通用操作以及基本接口;

  • QFileDevice:Qt5新增加的類,提供了有關文件操作的通用實現。

  • QFlie:訪問本地文件或者嵌入資源;

  • QTemporaryFile:創建和訪問本地文件系統的臨時文件;

  • QBuffer:讀寫QbyteArray, 內存文件;

  • QProcess:運行外部程序,處理進程間通訊;

  • QAbstractSocket:所有套接字類的父類;

  • QTcpSocket:TCP協議網絡數據傳輸;

  • QUdpSocket:傳輸 UDP 報文;

  • QSslSocket:使用 SSL/TLS 傳輸數據;

文件系統分類:

  • 順序訪問設備:

是指它們的數據只能訪問一遍:從頭走到尾,從第一個字節開始訪問,直到最後一個字節,中途不能返回去讀取上一個字節,這其中,QProcess、QTcpSocket、QUdpSoctet和QSslSocket是順序訪問設備。

  • 隨機訪問設備:

可以訪問任意位置任意次數,還可以使用 QIODevice::seek() 函數來重新定位文件訪問位置指針,QFile、QTemporaryFile 和 QBuffer 是隨機訪問設備。

 

二、QFile 讀寫文件:

在 ui 界面上拖兩個按鈕和一個文本編輯控件,如下:

代碼如下:

// 讀文件
void Widget::on_btnReadFile_clicked()
{
    // 獲取文件路徑
    QString filePath = QFileDialog::getOpenFileName();
    if (!filePath.isEmpty())
    {
        // 根據文件路徑實例化一個文件對象
        QFile file(filePath);
        
        // 以只讀方式打開文件
        if (file.open(QFile::ReadOnly))
        {
            // 讀取文件:一次讀取文件中所有內容
//            QByteArray buf = file.readAll();
            
            // 讀取文件:一行一行讀取
            QByteArray buf;
            while (!file.atEnd())
            {
                buf += file.readLine();
            }
            
            // 注意:默認情況下,如果文件中含有中文時,只有 UTF8 格式的文件能正常讀取,
            // 其他格式的文件讀取出的中文數據都是亂碼。
            
            // 顯示到 textEdit 上
            ui->textEdit->setText(buf);
        }
        
        // 關閉文件
        file.close();
    }
}

// 寫文件
void Widget::on_btnWriteFile_clicked()
{
    // 保存文件路徑
    QString filePath = QFileDialog::getSaveFileName();
    if (!filePath.isEmpty())
    {
        // 根據文件路徑實例化一個文件對象
        QFile file(filePath);
        
        // 以只寫方式打開文件
        if (file.open(QFile::WriteOnly))
        {
            // 獲取 textEdit 中內容;toPlainText 表示獲取 textEdit 中內容的純文本數據
            QString text = ui->textEdit->toPlainText();
            
            // 寫入文件:並將文件格式設置爲 utf8
//            file.write(text.toUtf8());
            
            // 寫入文件:將數據轉換成標準 C++ 的 char* 格式;
            // 生成的文件還是 utf8 格式,即默認寫入的數據格式就是 utf8;
//            file.write(text.toStdString().data());
            
            // 寫入文件:文件格式爲本地平臺8位編碼(windows 下默認爲 ANSI)
            file.write(text.toLocal8Bit());
        }
        
        // 關閉文件
        file.close();
    }
}

QFileDialog 的使用參考 Qt學習筆記(十二):標準文件對話框

 

三、QFileInfo 獲取文件信息:

// 獲取文件路徑
QString filePath = QFileDialog::getOpenFileName();
if (!filePath.isEmpty())
{
    QFileInfo info(filePath);
    qDebug() << info.absoluteFilePath();    // 獲取包含文件名的絕對路徑
    qDebug() << info.absolutePath();        // 獲取不包含文件名的絕對路徑

    qDebug() << info.fileName();            // 獲取文件名(不包含路徑)
    qDebug() << info.filePath();            // 獲取文件名(包括路徑,絕對的或相對的)
    qDebug() << info.path();                // 獲取文件路徑(不包含文件名)

    // 獲取文件的創建日期和事件("年-月-日 時:分:秒:毫秒")
    qDebug() << info.created().toString("yyyy-MM-dd HH:mm:ss:zzz");

    qDebug() << info.exists();              // 判斷文件是否存在

    qDebug() << info.suffix();              // 獲取文件後綴

    qDebug() << info.isExecutable();        // 是否是可執行文件
    qDebug() << info.isDir();               // 是否是目錄
    qDebug() << info.isFile();              // 是否是文件
    qDebug() << info.isHidden();            // 是否是隱藏文件
}

 

四、QDataStream 讀寫文件:

QDataStream 類提供二進制數據的序列化,到一個 IO 設備。

數據流是編碼信息的二進制流,它完全獨立於主機的操作系統、CPU 或字節順序。例如,通過 windows 下 PC 編寫的數據流,可以被運行在 Solaris 上的 Sun SPARC 讀取。

還可以使用數據流來讀取/寫入未經編碼的原始二進制數據。如果想要“解析”輸入流,請參閱 QTextStream。

QDataStream 類實現了 c++ 基本數據類型的序列化,如 char、short、int、char * 等。更復雜數據的序列化是通過將數據分解爲基本單元來實現的。

QDataStream 可以用來操作圖片、音頻、視頻等非文本數據。

寫文件:

// 寫文件
void Widget::on_btnWriteFile_clicked()
{
    QFile file("file.txt");
    
    // 以只寫方式打開文件
    if (file.open(QIODevice::WriteOnly))
    {
        // 根據文件對象實例化一個數據流,向數據流裏寫數據,就是向文件裏寫數據
        QDataStream stream(&file);   
        
        // 使用輸出字符寫數據,可以寫字符串,也可以整型,或者其他類型的數據;
        // 注意:因爲寫入的是二進制數據,所以即使寫入的是 .txt 文件,文件中也是亂碼;
        stream << QString("主要看氣質") << 22;
        
        file.close(); // 關閉文件
    }
    
    qDebug() << "寫文件成功";
}

讀文件:

// 讀文件
void Widget::on_btnReadFile_clicked()
{
    QFile file("file.txt");
    if (!file.exists())
    {
        qDebug() << "文件不存在";
    }
    else
    {
        // 以只讀方式打開文件
        if (file.open(QFile::ReadOnly))
        {
            // 創建數據流對象
            QDataStream stream(&file);
            
            QString str;
            int a;
            
            // 讀取數據。
            // 注意:讀取數據的類型和順序,需要和寫入數據的類型和順序 保持一致.
            stream >> str >> a;
            
            // Qt 默認寫入的數據是 utf8 格式的
            qDebug() << str.toUtf8().data() << a;
            
            file.close(); // 關閉文件
        }
    }
}

 

使用 QDataStream 讀取圖片,並轉換成 base64 字符串:

// 讀文件
void Widget::on_btnReadFile_clicked()
{
    // 獲取文件路徑
    QString filePath = QFileDialog::getOpenFileName();
    if (!filePath.isEmpty())
    {
        // 創建文件對象
        QFile file(filePath);
        
        // 以只讀方式打開文件
        if (file.open(QFile::ReadOnly))
        {
            // 創建數據流
            QDataStream stream(&file);
            
            char *buf = new char[1024];
            QByteArray array;
            
            // 循環讀取數據
            while (!stream.atEnd())
            {
                // 讀取數據到緩衝區 buf 中,最多讀取 1024 個字節,返回實際讀取的字節數;
                int len = stream.readRawData(buf, 1024);

                // 將讀取的二進制數據轉換成 字節數組
                array.append(QByteArray(buf, len));
            }
            delete buf;
            
            // 將讀取的數據轉換成 base64 字符串
            QString str = QString(array.toBase64());
            ui->textEdit->setText(str);
            
            // 不知道爲什麼此處的 qDebug() 方法不能輸出!!!
            qDebug() << str;
            
            file.close(); // 關閉文件
        }
    }
}

讀取結果:

使用 QDataStream 將 base64 字符串轉換成圖片:將上圖 textEdit 中的數據寫入圖片;

// 寫文件
void Widget::on_btnWriteFile_clicked()
{
    // 獲取保存文件路徑
    QString filePath = QFileDialog::getSaveFileName();
    if (!filePath.isEmpty())
    {
        // 創建文件對象
        QFile file(filePath);
        
        // 以只寫方式打開文件
        if (file.open(QFile::WriteOnly))
        {
            // 獲取 textEdit 上的文本信息
            QString text = ui->textEdit->toPlainText();
            
            // 將 base64 數據轉換成 字節數組
            QByteArray array = QByteArray::fromBase64(text.toUtf8());
            
            // 創建數據流
            QDataStream stream(&file);
            
            // 寫入數據:參數1表示緩存數據,參數2表示緩存數據的字節長度;返回實際寫入的字節數。
            int len = stream.writeRawData(array.data(), array.length());
            qDebug() << QString::number(len);
            
            file.close(); // 關閉文件
        }
    }
}

 

上面是使用 QDataStream 讀寫圖片,並和 base64 字符串的互相轉換,比較麻煩;Qt 還有更簡單的方法讀寫圖片數據,並和 base64 字符串互相轉換,如下所示:

讀取圖片數據,並轉換成 base64 字符串:

// 讀文件
void Widget::on_btnReadFile_clicked()
{
    // 獲取文件路徑
    QString filePath = QFileDialog::getOpenFileName();
    if (!filePath.isEmpty())
    {
        // 聲明字節數組
        QByteArray array;
        // 聲明緩衝區,指向字節數組(當向緩衝區寫入數據時,就是在向字節數組中寫入數據)
        QBuffer buf(&array);
        
        // 將圖片數據保存到緩衝區
        QPixmap pixmap(filePath);
        pixmap.save(&buf, "jpg");
        
        // 將數據轉換成 base64 字符串
        QString str = QString(array.toBase64());
        ui->textEdit->setText(str);
        qDebug() << str;
    }
}

將 base64 字符串數據保存爲圖片:

// 寫文件
void Widget::on_btnWriteFile_clicked()
{
    // 獲取保存文件路徑
    QString filePath = QFileDialog::getSaveFileName();
    if (!filePath.isEmpty())
    {
        // 獲取 textEdit 上的數據
        QString str = ui->textEdit->toPlainText();
        
        // 從給定字節數組加載一個圖片對象
        QPixmap pixmap;
        pixmap.loadFromData(QByteArray::fromBase64(str.toLocal8Bit()));
        
        // 保存圖片
        pixmap.save(filePath);
    }
}

 

五、QTextStream 操作文件:

QTextStream 類爲讀寫文本提供了一個方便的接口。

QTextStream 可以在 QIODevice、QByteArray 或 QString 上操作。使用 QTextStream 的流操作符,可以方便地讀寫單詞、行和數字。對於生成文本,QTextStream 支持字段填充和對齊的格式化選項,以及數字的格式化。

使用 QTextStream 讀取控制檯輸入和寫入控制檯輸出也是常見的。QTextStream 可識別區域設置,並將使用正確的編解碼器自動解碼標準輸入。

寫入文件:

// 寫文件
void Widget::on_btnWriteFile_clicked()
{
    // 創建文件對象
    QFile file("file.txt");
    
    // 以只寫方式打開文件
    if (file.open(QFile::WriteOnly))
    {
        // 創建文本流對象
        QTextStream stream(&file);
        
        // 設置寫入文件的編碼方式(默認情況下是根據平臺默認的編碼)
        stream.setCodec("UTF-8");
        
        // 向流中寫數據
        stream << QString("主要看氣質") << 250;
        
        // 關閉文件
        file.close();
    }
}

 

寫入的文件爲:

可以發現,寫入的兩個數據沒有分隔,而是緊挨在一起的;這種情況下如果使用下面的方法讀取數據,就無法讀出正確的數據:

// 讀文件
void Widget::on_btnReadFile_clicked()
{
    // 創建文件對象
    QFile file("file.txt");
    
    // 以只讀方式打開文件
    if (file.open(QFile::ReadOnly))
    {
        // 創建文本流對象
        QTextStream stream(&file);
        
        // 設置寫入文件的編碼方式(默認情況下是根據平臺默認的編碼)
        stream.setCodec("UTF-8");
        
        QString str;
        int a;
        
        // 讀取數據
        stream >> str >> a;
        qDebug() << str.toUtf8().data() << a;
        
        // 關閉文件
        file.close();
    }
}

輸出結果如下:這是因爲讀取的數據全部給了變量 str,而整型變量 a 沒有接收到數據,只有初始值 0.

 

六、QBuffer:表示一個內存緩衝區

QBuffer 類爲 QByteArray 提供一個 QIODevice 接口。

QBuffer 允許我們使用 QIODevice 接口訪問 QByteArray。QByteArray 被視爲一個標準的隨機訪問文件。

QBuffer 相當於一個內存文件,也可以向其中讀寫數據:

    // 聲明一個內存緩衝區(相當於一個內存文件,也可以讀寫數據)
    QBuffer buf;
    
    // 以只寫方式打開內存緩衝區
    if (buf.open(QFile::WriteOnly))
    {
        // 向內存緩衝區寫入數據
        buf.write("hello");
        buf.write("nihao");
        buf.write("how are you");
        
        buf.close(); // 關閉緩衝區
    }
    
    // 從緩衝區中讀取數據
    // 可以看到,向內存緩衝區中寫的多條數據,是緊挨在一起的
    qDebug() << buf.buffer();

QBuffer 可以和 QByteArray 一起使用,用 QByteArray 來存儲 QBuffer 緩衝區中的數據:

    // 聲明一個字節數組
    QByteArray array;
    
    // 聲明一個內存緩衝區,指向一個字節數組;
    // 當向緩衝區中寫入數據時,就是在向字節數組中寫入數據;
    QBuffer buf(&array);
    
    // 以只寫方式打開內存緩衝區
    if (buf.open(QFile::WriteOnly))
    {
        // 向內存緩衝區寫入數據
        buf.write("hello");
        buf.write("nihao");
        buf.write("how are you");
        
        buf.close(); // 關閉緩衝區
    }
    
    // 從緩衝區中讀取數據
    // 可以看到,向內存緩衝區中寫的多條數據,是緊挨在一起的
    qDebug() << buf.buffer();
    qDebug() << "array:" << array;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章