Qt的文件操作

1 文本文件读写

1.1 用QFile读写文本文件

QFile类是直接与IO设备打交道,进行文件读写的类。

[virtual] bool QFile::open(OpenMode mode);//打开文件。并指定模式
enum QIODevice::OpenModeFlag
{
	QIODevice::ReadOnly,//只读,用于载入文件
	QIODevice::WriteOnly,//只写,用于保存文件
	QIODevice::ReadWrite,//读写方式
	QIODevice::Append,//添加至尾部
	QIODevice::Truncate,//删除全部内容后打开
	QIODevice::Text//文本方式
};
[virtual] void QFileDevice::close();//关闭文件,并指定模式

QByteArray QIODevice::readAll();//读出所有文件内容
qint64 QIODevice::readLine(char *data, qint64 maxSize)//读一行,会自动添加 \n!!!!!!!!
qint64 QIODevice::write(const char *data, qint64 maxSize);//写入到文件
//用QFile从文件中读,可一次全部读出或者读一行
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);//创建QFile对象并指定文件名
if(!aFile.exists()) //文件不存在
	return false;
	
if (!aFile.open(QIODevice::ReadOnly | QIODevice::Text))
	return false;
QByteArray data = aFile.readAll()

/*
while (!aFile.atEnd())
{
	QByteArray line = aFile.readLine();//读一行文本,会自动添加 \n!!!!!
	QString str=QString::fromLocal8Bit(line); //从字节数组转换为字符串
    str.truncate(str.length()-1); //去除结尾增加的\n,便于显示
}
*/
aFile.close();
//用QFile向文件中写,一次全部写入
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;
	
QFile aFile(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();

1.2 用QFile和QTextStream结合读写文本文件

QTextStream可以和QFile、QTemporary、QBuffer、QTcpSocket、QUdpSocket等QIODevice类结合使用

QString QTextStream::readAll();
QString QTextStream::readLine(qint64 maxlen = 0);//读取文件的一行,不会自动添加 \n!!!!!
QTextStream &QTextStream::operator<<(const QString &string);//重载插入运算符,写入QString
void QTextStream::setAutoDetectUnicode(bool enabled);
//用QFile结合QTextStream从文件中读
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;
	
QFile aFile(aFileName);
if (!aFile.exists()) //文件不存在
	return false;
if (!aFile.open(QIODevice::ReadOnly | QIODevice::Text))
	return false;
	
QTextStream aStream(&aFile); //用文本流读取文件,并绑定文件对象
aStream.setAutoDetectUnicode(true); //自动检测Unicode,才能正常显示文档内的汉字
QString str = aStream.readAll();//一次读取全部内容,返回为QString

/*
while (!aStream.atEnd())
	QString str = aStream.readLine();//读取文件的一行,不会自动添加 \n!!!!!
*/

aFile.close();//关闭文件
//用QFile结合QTextStream向文件中写
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;
	
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();//关闭文件
  • 解决中文乱码的问题

    用QTextStream读或写有中文的文本文件时,为了能正确识别Unicode码,需要调用setAutoDetectUnicode函数,否则会出现乱码。
    我们也可以在应用程序中进行全局的设置,使用UTF-8编码解码器,使得应用程序支持Unicode。

#include <QApplication>
#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();
}

2 二进制文件读写QFile和QDataStream

除了文本文件,其它需要按一定格式定义读写的文件称为二进制文件,写入时要按一定格式写入,读出时也要按照这个格式读出。

  • Qt使用QFile和QDataStream进行二进制文件的读写,QFile负责文件的IO设备接口,即与文件的物理交互QDataStream以数据流的方式读取文件内容或写入文件
  • 根据QDataStream保存文件时使用的数据编码的方式不同,可保存为两种文件。一种是用Qt预定义编码保存各种类型的文件,后缀为.stm,每种类型由Qt编码,值与Qt版本有关。另一种是标准编码数据文件,后缀为.dat,写入时完全使用数据的二进制原始内容。

2.1 Qt预定义编码文件stm

下面的代码保存一个表格,保存为stm格式。

//保存为Qt预定义编码文件stm
QString curPath=QDir::currentPath();
QString aFileName = QFileDialog::getSaveFileName(this,tr("选择保存文件"),curPath,"Qt预定义编码数据文件(*.stm)");
if (aFileName.isEmpty())
	return; 
if  (saveDataAsStream(aFileName))
	QMessageBox::information(this,"提示消息","文件已经成功保存!");

bool MainWindow::saveDataAsStream(QString &aFileName)
{
    QFile aFile(aFileName);//以文件方式读出
    if (!(aFile.open(QIODevice::WriteOnly | QIODevice::Truncate)))
        return false;
    QDataStream aStream(&aFile);
    aStream.setVersion(QDataStream::Qt_5_9); //设置版本号,写入和读取的版本号要兼容

    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;
}
//读取Qt预定义编码文件stm
void MainWindow::on_actOpen_triggered()
{
    QString curPath=QDir::currentPath();
    QString aFileName=QFileDialog::getOpenFileName(this,tr("打开一个文件"),curPath,"流数据文件(*.stm)");
    if (aFileName.isEmpty())
        return; 
    if  (openDataAsStream(aFileName)) //保存为流数据文件
         QMessageBox::information(this,"提示消息","文件已经打开!");
}

bool MainWindow::openDataAsStream(QString &aFileName)
{
    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;
}
  • 用这种方式读写操作都很方便,特别是对于Qt的一些内置类型。
  • 但是拓展性不强,其它的工具无法读取,因为它无法解析Qt的编码,只有Qt才可以。

2.2 标准编码文件dat

  • 字节序问题
    字节序分为小端字节序和大端字节序,小端字节序低字节数据放在内存低地址处,大端字节序低字节数据放在内存高地址处。X86计算机都是小端字节序的,一些嵌入式平台使用的arm计算机是大端字节序的。读出文件时,我们要指定它的字节序,这样才能正确读取。写入文件时,我们也要注意字节序的设置。在跨平台使用dat文件时尤其需要注意!!!!
int QDataStream::writeRawData(const char *s, int len);
int QDataStream::readRawData(char *s, int len);
QDataStream &QDataStream::writeBytes(const char *s, uint len);
QDataStream &QDataStream::readBytes(char *&s, uint &len);
  • writeBytes函数适用于写入字符串数据,在写入数据时,它会先写入len值quint32,表示字符串的长度,接着再写入len个从指针s获得的数据。这样在读取时,readBytes函数就会自动读取长度len,从而避免了字符串长度一般不定的问题。
  • 注意写出和读入的函数要匹配!!!!
//保存为标准编码文件dat
QString curPath=QDir::currentPath();
QString aFileName=QFileDialog::getSaveFileName(this,tr("选择保存文件"),curPath,"二进制数据文件(*.dat)");
if (aFileName.isEmpty())
	return;
if  (saveBinaryFile(aFileName))
	QMessageBox::information(this,"提示消息","文件已经成功保存!");

bool MainWindow::saveBinaryFile(QString &aFileName)
{ 
    QFile aFile(aFileName); 
    if (!(aFile.open(QIODevice::WriteOnly)))
        return false;

    QDataStream aStream(&aFile); //用文本流读取文件
    aStream.setByteOrder(QDataStream::LittleEndian);//windows平台,保存为小端格式

    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,然后是字符串

        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中读入
QString curPath=QDir::currentPath();//系统当前目录
QString aFileName=QFileDialog::getOpenFileName(this,tr("打开一个文件"),curPath,"二进制数据文件(*.dat)");
if (aFileName.isEmpty())
	return;
if  (openBinaryFile(aFileName)) //保存为流数据文件
	QMessageBox::information(this,"提示消息","文件已经打开!");

bool MainWindow::openBinaryFile(QString &aFileName)
{
    QFile aFile(aFileName); 
    if (!(aFile.open(QIODevice::ReadOnly)))
        return false;

    QDataStream aStream(&aFile); //用文本流读取文件
    aStream.setByteOrder(QDataStream::LittleEndian);//保存的时候是小端

    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
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值