Qt基础 | 文本文件的读写 | 二进制文件读写 | 文件目录操作类

一、文本文件的读写

文本文件是指以纯文本格式存储的文件,例如用Qt编写的 C++ 程序的.h与.cpp文件。HTML与XML 文件也是纯文本文件,只是其读取之后需要对内容进行解析之后再显示。

  Qt 提供了两种读写纯文本文件的基本方法,

  • 一种是用 QFile 类的 IODevice 读写功能直接进行读写
  • 另一种是利用 QFile和QTextStream 结合起来,用流的方法进行文件读写。

1.QFile读写文本文件

  QFile类是直接与 IO 设备打交道,进行文件读写操作的类,使用 QFile 可以直接打开或保存文本文件。

读取文件

  通过QFileDialog对话框选择一个文件,利用该文件名实例化QFile对象,检查文件是否存在后,利用open()函数打开文件,利用readAll()函数读取所有数据。

示例:

QString curPath=QDir::currentPath();//获取系统当前目录
QString dlgTitle="打开一个文件"; //对话框标题
QString filter="程序文件(*.h *.cpp);;文本文件(*.txt);;所有文件(*.*)"; //文件过滤器
QString aFileName=QFileDialog::getOpenFileName(this,dlgTitle,curPath,filter);

if (aFileName.isEmpty())
	return;

QFile   aFile(aFileName);
//    aFile.setFileName(aFileName);

if (!aFile.exists()) //文件不存在
    return false;

if (!aFile.open(QIODevice::ReadOnly | QIODevice::Text))
    return false;

ui->textEditDevice->setPlainText(aFile.readAll());
// while (!aFile.atEnd())
// {
//     QByteArray line = aFile.readLine();//自动添加 \n
//     QString str=QString::fromLocal8Bit(line); //从字节数组转换为字符串
//     str.truncate(str.length()-1); //去除结尾增加的空行
//     ui->textEditDevice->appendPlainText(str);
// }
aFile.close();

注意事项:

  • QFile::open() 函数打开文件时需要传递 QlODevice::OpenModeFlag 枚举类型的参数 ,决定文件以什么方式打开, 这些取值可以组合

    QlODevice::OpenModeFlag 主要取值如下:

    • QIODevice::ReadOnly:只读方式打开文件,用于载入文件。
    • QIODevice::WriteOnly: 只写方式打开文件, 用于保存文件,隐含着Truncate,即删除文件原有的内容。
    • QIODevice::ReadWrite:读写方式打开文件
    • QIODevice::Append:以添加模式打开文件,新写入文件的数据添加到文件尾部
    • QIODevice::Truncate: 截取方式打开文件, 文件原有的内容全部被删除
    • QIODevice::Text:文本方式打开文件,读取时“\n”被自动翻译为换行符,写入时字符串结束符会自动翻译为系统平台的编码,如Windows平台下是“\r\n"
  • readAll()函数适合读取小文件或已知大小的文件,对于大文件,使用 readAll() 可能会消耗大量内存,因为它会一次性读取所有数据到内存中。在处理大文件时,可能需要考虑使用分块读取。

  • readLine()函数

    • 按行读取数据,每次调用返回一行。返回一个 QByteArray
    • 适合处理文本文件或需要逐行处理数据的场景。
    • 可以处理大文件,因为它一次只读取一行。
    • 需要在循环中调用,直到返回空的 QByteArray 表示读取完毕。

写入(保存)文件

  通过QFileDialog对话框选择一个目标文件,利用该文件名实例化QFile对象,检查文件是否存在后,利用open()函数打开该文件,使用的模式是 QIODevice::WriteOnly I QIODevice::Text,将 QPlaintextEdit组件的文本导出为字符串 ,然后转换为 UTF8 编码的字节数组 strBytes,然后调用 QFile :write() 函数将字节数组内容写入文件。

示例:

QString curPath=QDir::currentPath();//获取系统当前目录
QString dlgTitle="另存为一个文件"; //对话框标题
QString filter="h文件(*.h);;c++文件(*.cpp);;文本文件(*.txt);;所有文件(*.*)"; //文件过滤器
QString aFileName=QFileDialog::getSaveFileName(this,dlgTitle,curPath,filter);

if (aFileName.isEmpty())
    return;

saveTextByIODevice(aFileName);
//用IODevice方式保存文本文件
QFile   aFile(aFileName);
//    aFile.setFileName(aFileName);

if (!aFile.open(QIODevice::WriteOnly | QIODevice::Text))
    return false;

QString str=ui->textEditDevice->toPlainText();//整个内容作为字符串

QByteArray  strBytes=str.toUtf8();//转换为字节数组
//    QByteArray  strBytes=str.toLocal8Bit();

aFile.write(strBytes,strBytes.length());  //写入文件

aFile.close();

2.QFile与QTextStream 结合读写文本文件

  QTextStream与 IO 读写设备结合 ,为数据读写提供了一些方便的方法的类,QTextStream可以与 QFile、QTemporaryFile、 QBuffer、QTcpSocket、QUdpSocket等IO 设备类结合使用。

用文本流读取文件

  在创建 QTextStream 实例时传递一个 QFile 对象,这样 QFile 对象和 QTextStream 对象就结合在一起了,利用 QTextStream 可读写文件。如果文本文件里有汉字,需要设定为自动识别 Uni code码,即调用 setAutoDetectUnicode(true) 函数。

示例:

QString curPath=QDir::currentPath();//获取系统当前目录
//调用打开文件对话框打开一个文件
QString aFileName=QFileDialog::getOpenFileName(this,"打开一个文件",curPath,
             "程序文件(*.h *cpp);;文本文件(*.txt);;所有文件(*.*)");

if (aFileName.isEmpty())
    return; //如果未选择文件,退出

//打开文件
QFile   aFile(aFileName);

if (!aFile.exists()) //文件不存在
    return false;

if (!aFile.open(QIODevice::ReadOnly | QIODevice::Text))
    return false;

QTextStream aStream(&aFile); //用文本流读取文件
//    aStream.setAutoDetectUnicode(true); //自动检测Unicode,才能正常显示文档内的汉字

ui->textEditStream->setPlainText(aStream.readAll());

//    while (!aStream.atEnd())
//    {
//        str=aStream.readLine();//读取文件的一行
//        ui->textEditStream->appendPlainText(str); //添加到文本框显示
//    }

aFile.close();//关闭文件

写入文本流(保存文件)

示例:

QString curPath=QDir::currentPath();//获取系统当前目录
QString dlgTitle="另存为一个文件"; //对话框标题
QString filter="h文件(*.h);;c++文件(*.cpp);;文本文件(*.txt);;所有文件(*.*)"; //文件过滤器

QString aFileName=QFileDialog::getSaveFileName(this,dlgTitle,curPath,filter);

if (aFileName.isEmpty())
return;

//用QTextStream保存文本文件
QFile   aFile(aFileName);

if (!aFile.open(QIODevice::WriteOnly | QIODevice::Text))
    return false;

QTextStream aStream(&aFile); //用文本流读取文件
//    aStream.setAutoDetectUnicode(true); //自动检测Unicode,才能正常显示文档内的汉字

QString str=ui->textEditStream->toPlainText(); //转换为字符串

aStream<<str; //写入文本流


//    QTextDocument   *doc;       //文本对象
//    QTextBlock      textLine;   //文本中的一段
//    doc=ui->textEditStream->document(); //QPlainTextEdit 的内容保存在一个 QTextDocument 里
//    int cnt=doc->blockCount();//QTextDocument分块保存内容,文本文件就是硬回车符是一个block,

//    QString str;
//    for (int i=0; i<cnt; i++) //扫描所有 blobk
//    {
//         textLine=doc->findBlockByNumber(i);//用blobk编号获取block,就是获取一行
//         str=textLine.text(); //转换为文本,末尾无\n
//         aStream<<str<<"\n";
//    }

aFile.close();//关闭文件

3.解决中文乱码问题

  在使用 QTextStream 读写有中文内容的文本文件时,为了能正确识别 Unicode 码, 需要调用setAutoDetectUnicode(true),设置 QTextStream 可以自动识别 Unicode 码。 如果不做此设置,读取文件的中文将是乱码,无法正常显示。

  为解决 Unicode 的识别问题,可以在应用程序中做全局的设置 ,使得应用程序支持 Unicode。方法是在main()函数中使用QTextCodec类进行编码设置。例如:

#include    <QTextCodec>

int main(int argc, char *argv[])
{
    //解决汉字乱码问题
    QTextCodec *codec = QTextCodec::codecForName("UTF-8"); //查找编解码器对象
    QTextCodec::setCodecForLocale(codec); 		  //为当前区域设置指定的编解码器

    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}
  • QTextCodec是Qt框架中用于文本编解码的类。

  • codecForName函数–用于查找和返回与给定名称最匹配的编解码器对象

    [static] QTextCodec *QTextCodec::codecForName(const QByteArray &name)
    [static] QTextCodec *QTextCodec::codecForName(const char *name)
    
    • 函数说明:

      用于查找和返回与给定名称最匹配的编解码器对象。匹配过程不区分大小写,意味着"UTF-8"、"utf-8"和"UTF-8"都会被认为是相同的。如果没有找到匹配的编解码器,函数将返回nullptr

    • 示例:

      #include <QTextCodec>
      
      int main() {
          // 获取UTF-8编解码器
          QTextCodec *codec = QTextCodec::codecForName("UTF-8");
      
          if (codec) {
              // 使用编解码器进行编码转换
              QByteArray utf8Data = codec->fromUnicode("你好,世界!");
              qDebug() << "UTF-8 encoded data:" << utf8Data;
          } else {
              qDebug() << "Codec not found for UTF-8";
          }
      
          return 0;
      }
      
  • setCodecForLocale函数–为当前区域设置指定的编解码器

    [static] void QTextCodec::setCodecForLocale(QTextCodec *c)
    
    • 函数说明:

      用于为当前区域设置指定的编解码器,如果传递给函数的参数cnullptr,则会将编解码器重置为系统默认的编解码器。

二、二进制文件读写

  除了文本文件之外,其他需要按照一定的格式定义读写的文件都称为二进制文件。每种格式的二进制文件都有自己的格式定义,写入数据时按照一定的顺序写入,读出时也按照相应的顺序读出。例如,地球物理中常用的 SEG-Y 格式文件,必须按照其标准格式要求写入数据才符合这种文件的格式规范,该取数据时也需要按照格式定义来读出。

  Qt使用 QFile 和 QDataStream 进行二进制数据文件的读写。 QFile 负责文件的 IO 设备接口,即与文件的物理交互, QDataStream 以数据流的方式读取文件内容或写入文件内容。

  根据 QDataStrearm 保存文件时使用的数据编码的方式不同,可以保存为两种文件。

  • 用 Qt 预定义编码保存各种类型数据的文件,定义文件后缀为 “.stm”。Qt 预定义编码是指在写入某个类型数据,如整形数、字符串等到文件流时,使用 Qt 预定义的编码。

    QDataStrearm 以流操作写入这些数据时,并不知道文件里每个字节是如何存储的,但是知道数据写入的顺序,以及每次写入数据的类型,在文件数据读出时,只需要按照顺序和类型对应读出即可。

  • 标准编码数据文件,定义文件后缀为 “.dat”。在将数据写到文件时,完全使用数据的二进制原始内容,每个字节都有具体的定义,在读出数据时,只需要根据每个字节的定义写出数据即可。

两种文件的要点

  • 读写 stm 文件,

    这种方法使用简单,但是文件的格式不完全透明,不能创建用于交换的通用格式文件

  • 读写 dat 文件,

    这种方法创建通用格式文件,即文件格式完全透明

    以标准编码方式创建文件,使文件的每个字节都有具体的定义。用户在读取这种文件时,按照文件格式定义读取出每个字节数据并做解析即可,不管使用什么编程语言都可以编写读写文件的程序

使用 QDataStream 的流操作方式读写文件的特点

  • 读写操作都比较方便,支持读写各种数据类型,包括 Qt 的一些类,还可以为流数据读写扩展自定义的数据类型。读写某种类型的数据时,只要是流支持即可,而在文件内部是如何存储的,用户无需关心,由 Qt 预定义。
  • 写文件和读文件时必须保证使用的流版本兼容,即流的版本号相同,或读取文件的流版本号高于写文件时的流版本号。这是因为在不同的流版本中,流支持的数据类型的读写方式可能有所改变, 必须保证读写版本的兼容
  • 用这种方式保存文件时,写入数据采用 Qt 预定义的编码,即写入文件的二进制编码是由 Qt 预定义的,写多少个字节、字节是什么样的顺序,用户是不知道的。如果是由 QDataStream 读取数据, 只需按类型读出即可。若用其他编程语言来读取文件内容,就会存在问题。

1.Qt预定义编码文件的读写

1.1 保存(写入)stm文件

  保存为一个stm文件的过程:

  • 首先,通过文本对话框选择一个保存(写入)文件

    void MainWindow::on_actSave_triggered()
    { //以Qt预定义编码保存数据文件
        QString curPath=QDir::currentPath();
        QString aFileName=QFileDialog::getSaveFileName(this,tr("选择保存文件"),curPath,
                     "Qt预定义编码数据文件(*.stm)");
    
        if (aFileName.isEmpty())
            return; //
    
       if  (saveDataAsStream(aFileName)) //保存为流数据文件
           QMessageBox::information(this,"提示消息","文件已经成功保存!");
    }
    
  • 然后,创建 QFile 对象 aFile 打开文件,

  • 创建 QDataStream 对象 Stream 与 QFile 对象关联。

  • 在开始写数据流之前,为 QDataStream 对象 aStream 设置版本号,即调用setVersion()函数

    注意:以 Qt 的预定义类型编码保存的文件需要指定流版本号,因为每个版本的 Qt 对数据类型的编码可能有差别,需要保证写文件和读文件的流版本是兼容的

  • 接下来,按照需要保存数据的顺序写入文件流。

    • 在文件开始,先写入行数和列数,因为行数与列数关系到后面的数据是如何组织的
    • 接着,读取各列的表头并写入数据流
    • 然后逐行扫描表格的数据类型,将每一行的列数据写入数据流。数据流写入数据时都使用运算符“<<"。
    bool MainWindow::saveDataAsStream(QString &aFileName)
    {//将模型数据保存为Qt预定义编码的数据文件
        QFile aFile(aFileName);  //以文件方式读出
        if (!(aFile.open(QIODevice::WriteOnly | QIODevice::Truncate)))
            return false;
    
        QDataStream aStream(&aFile);
        aStream.setVersion(QDataStream::Qt_5_15); //设置版本号,写入和读取的版本号要兼容
    
        qint16  rowCount=theModel->rowCount(); //数据模型行数
        qint16  colCount=theModel->columnCount(); //数据模型列数
    
        aStream<<rowCount; //写入文件流,行数
        aStream<<colCount;//写入文件流,列数
    
    //获取表头文字
        for (int i=0;i<theModel->columnCount();i++)
        {
            QString str=theModel->horizontalHeaderItem(i)->text();//获取表头文字
            aStream<<str; //字符串写入文件流,Qt预定义编码方式
        }
    
    
    //获取数据区的数据
        for (int i=0;i<theModel->rowCount();i++)
        {
            QStandardItem* aItem=theModel->item(i,0); //测深
            qint16 ceShen=aItem->data(Qt::DisplayRole).toInt();
            aStream<<ceShen;// 写入文件流,qint16
    
            aItem=theModel->item(i,1); //垂深
            qreal chuiShen=aItem->data(Qt::DisplayRole).toFloat();
            aStream<<chuiShen;//写入文件流, qreal
    
            aItem=theModel->item(i,2); //方位
            qreal fangWei=aItem->data(Qt::DisplayRole).toFloat();
            aStream<<fangWei;//写入文件流, qreal
    
            aItem=theModel->item(i,3); //位移
            qreal weiYi=aItem->data(Qt::DisplayRole).toFloat();
            aStream<<weiYi;//写入文件流, qreal
    
            aItem=theModel->item(i,4); //固井质量
            QString zhiLiang=aItem->data(Qt::DisplayRole).toString();
            aStream<<zhiLiang;// 写入文件流,字符串
    
            aItem=theModel->item(i,5); //测井
            bool quYang=(aItem->checkState()==Qt::Checked);
            aStream<<quYang;// 写入文件流,bool型
        }
        aFile.close();
        return true;
    }
    

根据 saveDataAsStream() 函数的代码,可知 Qt 预定义编码保存的 stm 文件的格式,如下:

image-20240720141900333

image-20240720141932953

1.2 读取 stm 文件

  读取 stm 文件的过程:

  • 首先,通过文本对话框选择一个待读取的 stm 文件

    void MainWindow::on_actOpen_triggered()
    {
        QString curPath=QDir::currentPath();
    //调用打开文件对话框打开一个文件
        QString aFileName=QFileDialog::getOpenFileName(this,tr("打开一个文件"),curPath,
                     "Qt预定义编码数据文件(*.stm)");
    
        if (aFileName.isEmpty())
            return; //
    
        if  (openDataAsStream(aFileName)) //读取流数据文件
             QMessageBox::information(this,"提示消息","文件已经打开!");
    }
    
  • 然后,创建 QFile 对象 aFile 打开文件,

  • 创建 QDataStream 对象 Stream 与 QFile 对象关联。

  • 在开始读取数据流之前,为 QDataStream 对象 aStream 设置流版本号,即调用setVersion()函数,应该等于或高于数据保存时的流版本号

    注意:以 Qt 的预定义类型编码保存的文件需要指定流版本号,因为每个版本的 Qt 对数据类型的编码可能有差别,需要保证写文件和读文件的流版本是兼容的

  • 接下来,按照需要写入数据的顺序和类型,相应地读出每个数据

    • 文件里最早的两个数据是表格的行数和列数, 读出这两个数据,就能知道数据的行数和列数,并调用自定义函数resetTable()函数给数据模型复位,并设置其行数。
    • 然后,将保存的每行数据读入到数据模型的每个项中,这样窗口上的 QTableView 组件就可以显示数据了
    bool MainWindow::openDataAsStream(QString &aFileName)
    { //从Qt预定义流文件读入数据
        QFile aFile(aFileName);  //以文件方式读出
        if (!(aFile.open(QIODevice::ReadOnly)))
            return false;
    
        QDataStream aStream(&aFile); //用文本流读取文件
        aStream.setVersion(QDataStream::Qt_5_9); //设置流文件版本号
    
        qint16  rowCount,colCount;
        aStream>>rowCount; //读取行数
        aStream>>colCount; //列数
    
        this->resetTable(rowCount); //表格复位
    
        //获取表头文字
        QString str;
        for (int i=0;i<colCount;i++)
            aStream>>str;  //读取表头字符串
    
        //获取数据区文字,
        qint16  ceShen;
        qreal  chuiShen;
        qreal  fangWei;
        qreal  weiYi;
        QString  zhiLiang;
        bool    quYang;
        QStandardItem   *aItem;
        QModelIndex index;
    
        for (int i=0;i<rowCount;i++)
        {
            aStream>>ceShen;//读取测深, qint16
            index=theModel->index(i,0);
            aItem=theModel->itemFromIndex(index);
            aItem->setData(ceShen,Qt::DisplayRole);
    
            aStream>>chuiShen;//垂深,qreal
            index=theModel->index(i,1);
            aItem=theModel->itemFromIndex(index);
            aItem->setData(chuiShen,Qt::DisplayRole);
    
    
            aStream>>fangWei;//方位,qreal
            index=theModel->index(i,2);
            aItem=theModel->itemFromIndex(index);
            aItem->setData(fangWei,Qt::DisplayRole);
    
    
            aStream>>weiYi;//位移,qreal
            index=theModel->index(i,3);
            aItem=theModel->itemFromIndex(index);
            aItem->setData(weiYi,Qt::DisplayRole);
    
    
            aStream>>zhiLiang;//固井质量,QString
            index=theModel->index(i,4);
            aItem=theModel->itemFromIndex(index);
            aItem->setData(zhiLiang,Qt::DisplayRole);
    
            aStream>>quYang;//bool
            index=theModel->index(i,5);
            aItem=theModel->itemFromIndex(index);
            if (quYang)
                aItem->setCheckState(Qt::Checked);
            else
                aItem->setCheckState(Qt::Unchecked);
        }
    
        aFile.close();
        return true;
    }
    

2.标准编码文件的读写

2.1 保存为dat文件

  保存为 dat 文件的过程:

  • 首先,通过文本对话框选择保存(写入)文件

    void MainWindow::on_actSaveBin_triggered()
    {//保存二进制文件
        QString curPath=QDir::currentPath();
        //调用打开文件对话框选择一个文件
        QString aFileName=QFileDialog::getSaveFileName(this,tr("选择保存文件"),curPath,
                                                       "二进制数据文件(*.dat)");
        if (aFileName.isEmpty())
            return; //
    
        if  (saveBinaryFile(aFileName)) //保存为流数据文件
            QMessageBox::information(this,"提示消息","文件已经成功保存!");
    }
    
  • 然后,创建 QFile 对象 aFile 打开文件,

  • 创建 QDataStream 对象 Stream 与 QFile 对象关联。

  • 在保存为标准编码的二进制文件时,无须指定 QDataStream 版本,但是,如有必要,需要为文件指定字节顺序,字节顺序分为大端字节序和小端字节序

  • 使用 QdataStrearm 的 writeRawData() 和 writeBytes() 函数将数据写入到数据流中

    int QDataStream::writeRawData(const char *s, int len)
    QDataStream &QDataStream::writeBytes(const char *s, uint len)
    
    • writeRawData函数

      将 qint8、qintl6、qreal 等类型的数据保存到文件中

    • writeBytes函数

      • 写入操作首先写入一个quint32类型的值,表示随后要写入的字节数。
      • 然后,从缓冲区s开始,写入len个字节的数据。

      image-20240720151032344

    bool MainWindow::saveBinaryFile(QString &aFileName)
    { //保存为纯二进制文件
        QFile aFile(aFileName);  //以文件方式读出
        if (!(aFile.open(QIODevice::WriteOnly)))
            return false;
    
        QDataStream aStream(&aFile); //用文本流读取文件
    //    aStream.setVersion(QDataStream::Qt_5_9); //无需设置数据流的版本
        aStream.setByteOrder(QDataStream::LittleEndian);//windows平台
    //    aStream.setByteOrder(QDataStream::BigEndian);//QDataStream::LittleEndian
    
        qint16  rowCount=theModel->rowCount();
        qint16  colCount=theModel->columnCount();
    
        aStream.writeRawData((char *)&rowCount,sizeof(qint16)); //写入文件流
        aStream.writeRawData((char *)&colCount,sizeof(qint16));//写入文件流
    
    
    //获取表头文字
        QByteArray  btArray;
        QStandardItem   *aItem;
        for (int i=0;i<theModel->columnCount();i++)
        {
            aItem=theModel->horizontalHeaderItem(i); //获取表头item
            QString str=aItem->text(); //获取表头文字
            btArray=str.toUtf8(); //转换为字符数组
            aStream.writeBytes(btArray,btArray.length()); //写入文件流,长度uint型,然后是字符串内容
        }
    
    //获取数据区文字,
        qint8   yes=1,no=0; //分别代表逻辑值 true和false
        for (int i=0;i<theModel->rowCount();i++)
        {
            aItem=theModel->item(i,0); //测深
            qint16 ceShen=aItem->data(Qt::DisplayRole).toInt();//qint16类型
            aStream.writeRawData((char *)&ceShen,sizeof(qint16));//写入文件流
    
            aItem=theModel->item(i,1); //垂深
            qreal chuiShen=aItem->data(Qt::DisplayRole).toFloat();//qreal 类型
            aStream.writeRawData((char *)&chuiShen,sizeof(qreal));//写入文件流
    
            aItem=theModel->item(i,2); //方位
            qreal fangWei=aItem->data(Qt::DisplayRole).toFloat();
            aStream.writeRawData((char *)&fangWei,sizeof(qreal));
    
            aItem=theModel->item(i,3); //位移
            qreal weiYi=aItem->data(Qt::DisplayRole).toFloat();
            aStream.writeRawData((char *)&weiYi,sizeof(qreal));
    
            aItem=theModel->item(i,4); //固井质量
            QString zhiLiang=aItem->data(Qt::DisplayRole).toString();
            btArray=zhiLiang.toUtf8();
            aStream.writeBytes(btArray,btArray.length()); //写入长度,uint,然后是字符串
    //        aStream.writeRawData(btArray,btArray.length());//对于字符串,应使用writeBytes()函数
    
            aItem=theModel->item(i,5); //测井取样
            bool quYang=(aItem->checkState()==Qt::Checked); //true or false
            if (quYang)
                aStream.writeRawData((char *)&yes,sizeof(qint8));
            else
                aStream.writeRawData((char *)&no,sizeof(qint8));
        }
    
        aFile.close();
        return true;
    }
    

dat文件格式

image-20240720151238970

2.2 读取 dat 文件

  读取 dat 文件的过程:

  • 首先,通过文本对话框选择一个待读取的 dat 文件

    void MainWindow::on_actOpenBin_triggered()
    {//打开二进制文件
        QString curPath=QDir::currentPath();//系统当前目录
        QString aFileName=QFileDialog::getOpenFileName(this,tr("打开一个文件"),curPath,
                                                       "二进制数据文件(*.dat)");
        if (aFileName.isEmpty())
            return; //
    
        if  (openBinaryFile(aFileName)) //读取流数据文件
            QMessageBox::information(this,"提示消息","文件已经打开!");
    }
    
  • 然后,创建 QFile 对象 aFile 打开文件,

  • 创建 QDataStream 对象 Stream 与 QFile 对象关联。

  • 使用 setByteOrder() 为文件指定字节顺序,保证与写入文件时用的字节序一致

  • 使用 QdataStrearm 的 readRawData() 和 readBytes() 函数从数据流中读取数据

    int QDataStream::readRawData(char *s, int len)
    QDataStream &QDataStream::readBytes(char *&s, uint &l)
    
  • 读入到数据模型的每个项中,这样窗口上的 QTableView 组件就可以显示数据了

    bool MainWindow::openBinaryFile(QString &aFileName)
    {//打开二进制文件
        QFile aFile(aFileName);  //以文件方式读出
        if (!(aFile.open(QIODevice::ReadOnly)))
            return false;
    
        QDataStream aStream(&aFile); //用文本流读取文件
    //    aStream.setVersion(QDataStream::Qt_5_9); //设置数据流的版本
        aStream.setByteOrder(QDataStream::LittleEndian);
    //    aStream.setByteOrder(QDataStream::BigEndian);
    
        qint16  rowCount,colCount;
        aStream.readRawData((char *)&rowCount, sizeof(qint16));
        aStream.readRawData((char *)&colCount, sizeof(qint16));
    
        this->resetTable(rowCount);
    
    
        //获取表头文字,但是并不利用
        char *buf;
        uint strLen;  //也就是 quint32
        for (int i=0;i<colCount;i++)
        {
            aStream.readBytes(buf,strLen);//同时读取字符串长度,和字符串内容
            QString str=QString::fromLocal8Bit(buf,strLen); //可处理汉字
        }
    
    //获取数据区数据
        QStandardItem   *aItem;
    
        qint16  ceShen;
        qreal  chuiShen;
        qreal  fangWei;
        qreal  weiYi;
        QString  zhiLiang;
        qint8   quYang; //分别代表逻辑值 true和false
        QModelIndex index;
    
        for (int i=0;i<rowCount;i++)
        {
            aStream.readRawData((char *)&ceShen, sizeof(qint16)); //测深
            index=theModel->index(i,0);
            aItem=theModel->itemFromIndex(index);
            aItem->setData(ceShen,Qt::DisplayRole);
    
            aStream.readRawData((char *)&chuiShen, sizeof(qreal)); //垂深
            index=theModel->index(i,1);
            aItem=theModel->itemFromIndex(index);
            aItem->setData(chuiShen,Qt::DisplayRole);
    
            aStream.readRawData((char *)&fangWei, sizeof(qreal)); //方位
            index=theModel->index(i,2);
            aItem=theModel->itemFromIndex(index);
            aItem->setData(fangWei,Qt::DisplayRole);
    
            aStream.readRawData((char *)&weiYi, sizeof(qreal)); //位移
            index=theModel->index(i,3);
            aItem=theModel->itemFromIndex(index);
            aItem->setData(weiYi,Qt::DisplayRole);
    
            aStream.readBytes(buf,strLen);//固井质量
            zhiLiang=QString::fromLocal8Bit(buf,strLen);
            index=theModel->index(i,4);
            aItem=theModel->itemFromIndex(index);
            aItem->setData(zhiLiang,Qt::DisplayRole);
    
            aStream.readRawData((char *)&quYang, sizeof(qint8)); //测井取样
            index=theModel->index(i,5);
            aItem=theModel->itemFromIndex(index);
            if (quYang==1)
                aItem->setCheckState(Qt::Checked);
            else
                aItem->setCheckState(Qt::Unchecked);
        }
    
        aFile.close();
        return true;
    }
    

三、文件目录操作类

1.文件目录操作相关的类

  Qt 为文件和目录操作提供了一些类 ,利用这些类可以方便 实现一些操作。 Qt 提供的与文件和目录操作相关的类包括以下几个:

  • QCoreApplication:用于提取应用程序路径、程序名等文件信息
  • QFile:除了打开文件操作外,QFile 还有复制文件、删除文件等功能
  • QFilelnfo:用于提取文件的信息,包括路径、文件名、后缀等
  • QDir:用于提取目录或文件信息,获取一个目录下的文件或目录列表,创建或删除目录和文件,文件重命名等操作
  • QTemporaryDir和QTemporaryFile:用于创建临时目录和临时文件
  • QFileSystemWatcher:文件和目录监听类 ,监听目录下文件的添加 、删除等变化,监听文件修改变化

2.QCoreApplication类

  QCoreApplication 是为无 GUI 应用提供事件循环的类,是所有应用程序的基类,其子类 QGuiApplication 为有 GUI 界面的应用程序提供流控制和主要的设定,QGuiApplication 的子类QApplication 为基于 QWidget 的应用程序提供支持,包括界面的初始化等。创建的 Qt Widget Application 都是基于 QApplication 的,在 main() 函数里可以看到 QApplication的应用。

  QCoreApplication 提供了一些有用的静态函数,可以获取应用程序的名称、启动路径等信息

image-20240720155015371

3.QFile类

  除了打开文件提供读写操作外,QFile还有一些静态函数和成员函数用于文件操作。

QFile的一些静态函数

image-20240720155443971

QFile的对应成员函数

image-20240720155525503

4.QFileInfo类

  QFileInfo类的接口函数提供文件的各种信息。

QFileInfo常见接口函数和功能

image-20240720155913308

除了exists()是静态函数之外,其他都是公共接口函数。QFilelnfo 提供的这些函数可以提取文件的信息,包括目录名、文件基名(不带后缀) 、文件后缀等,利用这些函数可以实现灵活的文件操作。

5.QDir类

  QDir 是进行目录操作的类,在创建 QDir 时传递一个目录字符串作为当前目录,然后 QDir 函数就可以针对当前目录或目录下的文件进行操作 。

QDir的一些静态函数

image-20240720160831613

image-20240720160845320

QDir的一些公共接口函数

image-20240720161014099

QDir::Filter 枚举类型的常用取值:

  • QDir::AllDirs:列出所有目录名

  • QDir::Files:列出所有文件

  • QDir::Drives:列出所有盘符

  • QDir::NoDotAndDotDot:不列出特殊的符号,如“.“和”…"

  • QDir::AllEntries:列出目录下所有项目

6.QTemporaryDir和QTemporaryFile类

  QTemporaryDir 和 QTemporaryFile 是用于创建、删除临时目录的类,主要函数如下:

image-20240720161646870

  在系统临时目录 ,即 QDir::tempPath 目录下创建一个临时目录, 临时目录名称以QCoreApplication::applicationName() 为前缀,后加6个字符。临时目录可以设置为使用完后自动删除,即临时目录变量删除时,临时目录也删除。

  QTemporayFile 是用于创建临时文件的类 ,临时文件保存在系统临时目录下。临时文件以QCoreApplication::applicationName() 作为文件名, 以“XXXXXX” 6个随机数字作为文件后缀。将QTemporaryFile: :setAutoRemove() 函数设置为是否自动删除临时文件,QTemporaryFile::open() 函数用于打开临时文件,只有打开临时文件,才实际创建了此文件。

7.QFileSystemWatcher类

  QFileSystemWatcher 是对目录和文件进行监听的类。把某些目录或文件添加到 QFileSystemWatcher 对象的监听列表后,当目录下发生文件新建、删除等操作时会发射 directorChanged() 信号,当监听的文件发生修改、重命名等操作时, 会发射 fileChanged() 信号。所以,这个类在进行目录或文件监听时起作用。

QFileSystemWatcher的主要接口

image-20240720162435698

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值