QT 学习笔记(十三)

由于每次代码都是在原有程序上修改,因此除了新建项目,不然一般会在学完后统一展示代码。
提示:具体项目创建流程和注意事项见QT 学习笔记(一)
提示:具体项目准备工作和细节讲解见QT 学习笔记(二)

一、QDataStream 二进制文件读写

  • 生成一个新的项目,具体步骤过程见提示。

1. QDataStream 简介

  • QDataStream 提供了基于 QIODevice 的二进制数据的序列化。
  • 数据流是一种二进制流,这种流完全不依赖于底层操作系统、CPU 或者字节顺序(大端或小端)。例如,在安装了 Windows 平台的 PC 上面写入的一个数据流,可以不经过任何处理,直接拿到运行了 Solaris 的 SPARC 机器上读取。由于数据流就是二进制流,因此我们也可以直接读写没有编码的二进制数据,例如图像、视频、音频等。
  • QDataStream 既能够存取 C++ 基本类型,如 int、char、short 等,也可以存取复杂的数据类型,例如自定义的类。
  • 实际上,QDataStream 对于类的存储,是将复杂的类分割为很多基本单元实现的。
  • 结合 QIODevice,QDataStream 可以很方便地对文件、网络套接字等进行读写操作。
  • 那么,既然 QIODevice 提供了 read()、readLine() 之类的函数,为什么还要有 QDataStream 呢? DataStream 同 QIODevice 有什么区别?
  • 区别在于,QDataStream 提供流的形式,性能上一般比直接调用原始 API 更好一些

2. QDataStream 实际演示

2.1 QDataStream 读写文件操作

  • 在这里就不通过 ui 界面进行文件的操作演示了,直接通过代码执行操作。
  • 我们先编写一个文件,随后在对其进行读操作。
  • 因为,我们仍然需要打开文件,关联文件路径,所有,需要有头文件 #include < QFile >
  • 通过编写代码并运行,会在根目录下生成一个名为 test.txt 的文本文件,实现结果如下图所示:

在这里插入图片描述

  • 这里我们会发现,在 QT 的运行结果上没有任何显示结果,此时,我们打开在根目录下生成的 test.txt 文件,得到如下结果。

在这里插入图片描述

  • 这个 test.txt 文本文件我们打开后发现是乱码,这主要是因为 QDataStream 是对二进制文件进行操作,这导致我们直接打开是以乱码的形式展现出来。
  • 如果我们想要阅读 test.txt 文本文件的内容可以通过读文件的方式使其展现。
  • 唯一需要注意的是,这里必须按照写入的顺序,将数据读取出来。顺序颠倒的话,程序行为是不确定的,严重时会直接造成程序崩溃。
  • 通过编写代码,并运行,得到如下运行结果:

在这里插入图片描述

  • 在文件操作中,我们可以感受到 qDebug() 使用起来是略微有点不便的,可以通过定义一种转换方式,使其变为在 C++ 里面经常使用的 cout 进行输出,代码如下:
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"
  • 在这句代码当中,会先输入 [ 和文件路径,再输出该语句所在的行号和 ] ,最后输出我们所打印的内容,实现结果如下图所示:

在这里插入图片描述

2.2 实现代码——主窗口头文件 widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

    //写文件
    void writeData();

    //读文件
    void readData();

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

2.3 实现代码——主窗口源文件 widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QDataStream>
#include <QFile>
#include <QDebug>
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    writeData();
    readData();
}

Widget::~Widget()
{
    delete ui;
}

void Widget::writeData()
{
    //创建文件对象
    QFile file("../test.txt");

    //打开文件,以只写方式打开
    bool isok = file.open(QIODevice::WriteOnly);
    if(isok==true)
    {
        //创建数据流,和file文件关联
        //往数据流中写数据,相当于往文件里写数据
        QDataStream stream(&file);

        stream << QString("主要看气质") << 250;//结果文件里都是不可见的二进制数据

        file.close();

    }
}

void Widget::readData()
{
    //创建文件对象
    QFile file("../test.txt");

    //打开文件,以只读方式打开
    bool isok = file.open(QIODevice::ReadOnly);
    if(isok==true)
    {
        //创建数据流,和file文件关联
        //往数据流中读数据,相当于往文件里读数据
        QDataStream stream(&file);

        //读的时候,按写的顺序取数据
        QString str;
        int a;
        stream >> str >> a;
        //qDebug() << str.toUtf8().data() << a;
        cout << str.toUtf8().data() << a;

        file.close();

    }
}

二、QTextStream 文本文件读写

  • 生成一个新的项目,具体步骤过程见提示。

1. QTextStream 简介

  • 二进制文件比较小巧,却不是人可读的格式。而文本文件是一种人可读的文件。为了操作这种文件,我们需要使用 QTextStream 类。
  • QTextStream 和 QDataStream 的使用类似,只不过它是操作纯文本文件的。
  • QTextStream 会自动将 Unicode 编码同操作系统的编码进行转换,这一操作对开发人员是透明的。
  • 同时,它也会将换行符进行转换,同样不需要自己处理。
  • QTextStream 使用 16 位的 QChar 作为基础的数据存储单位,同样,它也支持 C++ 标准类型,如 int 等。实际上,这是将这种标准类型与字符串进行了相互转换。
  • 当使用 QDataStream 写入的时候,实际上会在要写入的内容前面,额外添加一个这段内容的长度值。而以文本形式写入数据,是没有数据之间的分隔的。因此,使用文本文件时,很少会将其分割开来读取,而是使用诸如使用:
QTextStream::readLine()//读取一行
QTextStream::readAll()//读取所有文本
  • 这种函数之后再对获得的 QString 对象进行处理。
  • 默认情况下,QTextStream 的编码格式是 Unicode,如果我们需要使用另外的编码,可以使用如下函数进行设置。
stream.setCodec("UTF-8");
  • 知识点补充:在 QT 的文件操作当中,有如下的打开方式:
枚举值描述
QIODevice::NotOpen未打开
QIODevice::ReadOnly以只读方式打开
QIODevice::WriteOnly以只写方式打开
QIODevice::ReadWrite以读写方式打开
QIODevice::Append以追加的方式打开,新增加的内容将被追加到文件末尾
QIODevice::Truncate以重写的方式打开,在写入新的数据时会将原有数据全部清除,游标设置在文件开头
QIODevice::Text在读取时,将行结束符转换成 \n;在写入时,将行结束符转换成本地格式,例如 Win32 平台上是 \r\n
QIODevice::Unbuffered忽略缓存

2. QTextStream 实际演示

2.1 QTextStream 读写文件操作

  • QTextStream 与 QDataStream 类似,在这里也不使用 ui 界面进行文件的操作演示了,直接通过代码执行操作。
  • 我们先编写一个文件,随后在对其进行读操作。
  • 通过编写代码并运行,会在根目录下生成一个名为 demo.txt 的文本文件,实现结果如下图所示:

在这里插入图片描述

  • 这里我们会发现,在 QT 的运行结果上没有任何显示结果,此时,我们打开在根目录下生成的 demo.txt 文件,得到如下结果。

在这里插入图片描述

  • 这个 demo.txt 文本文件我们打开后发现是正常的汉字和数字,这是因为 QTextStream 针对的是文本文档,可以直接被人们阅读。
  • 如果我们想要阅读 demo.txt 文本文件的内容可以通过读文件的方式使其展现。
    唯一需要注意的是,这里必须按照写入的顺序,将数据读取出来。顺序颠倒的话,程序行为是不确定的,严重时会直接造成程序崩溃。
  • 通过编写代码,并运行,得到如下运行结果:

在这里插入图片描述

  • 但是通过现象我们会发现最后多了一个 0 ,这是因为他直接将主要看气质和 250 看作为一个整体赋值给 str ,那么 a 就会没有赋值,变为 0。
  • 因此,这种读文件的方式是错误的。
  • 正确的读文件方法是在 ui 界面进行窗口的设计,通过 QTextStream::readAll() 的方式进行阅读,如下图现象所示。

在这里插入图片描述

2.2 实现代码——主窗口头文件 widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

    //写文件
    void writeData();

    //读文件
    void readData();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

2.3 实现代码——主窗口源文件 widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QTextStream>
#include <QFile>
#include <QFileDialog>
#include <QDebug>
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    writeData();
    readData();
}

Widget::~Widget()
{
    delete ui;
}

void Widget::writeData()
{
    QFile file;
    file.setFileName("../demo.txt");

    bool isok = file.open(QIODevice::WriteOnly);
    if(true == isok)
    {
        QTextStream stream(&file);

        //指定编码方式
        stream.setCodec("UTF-8");

        stream << QString("主要看气质") << 250;

        file.close();
    }
}

void Widget::readData()
{
    QFile file;
    file.setFileName("../demo.txt");

    bool isok = file.open(QIODevice::ReadOnly);
    if(true == isok)
    {
        QTextStream stream(&file);

        //指定编码方式
        stream.setCodec("UTF-8");

        QString str;
        int a;
        stream >> str >> a;

        //qDebug() << str << a;
        cout << str << a;

        file.close();
    }
}

void Widget::on_pushButton_clicked()
{
    QString path = QFileDialog::getOpenFileName(this,"open","../");
    if(false == path.isEmpty())
    {
        QFile file;
        file.setFileName(path);

        bool isok = file.open(QIODevice::ReadOnly);
        if(true == isok)
        {
            QTextStream stream(&file);

            //指定编码方式
            stream.setCodec("UTF-8");

            QString str = stream.readAll();
            ui->textEdit->setText(str);
        }
    }
}

三、QBuffer

  • 生成一个新的项目,具体步骤过程见提示。

1. QBuffer 简介和操作实现

  • QBuffer 与文件操作并没有太大关系,是放在内存里面的。
  • 在使用 QBuffer 的过程中,不需要在头文件下进行函数的声明,可以直接在构造函数中进行代码的编写,得到如下图所示现象。

在这里插入图片描述

  • 通过现象,我们可以发现,他将两个合为一行,连在一块。如果我们想要将其分行显示,需要 \n 。
  • 但这里需要注意的是不可以直接加 \n ,不然会被当成字符直接输出,这里需要使用转义字符。
  • 除此以外,我们也可以定义所编写的内容放到哪个缓冲区当中,具体结果如下图现象所示。

在这里插入图片描述

  • 此外,QBuffer 也可以与 QDataStream 配合使用,具体结果如下图现象所示。

在这里插入图片描述

  • 这里必须按照写入的顺序,将数据读取出来。读文件操作现象具体如下图所示

在这里插入图片描述

2. 实现代码——主窗口源文件 widget.cpp

  • 主窗口头文件 widget.h 没有变化。
#include "widget.h"
#include "ui_widget.h"
#include <QBuffer>//内存文件
#include <QDebug>
#include <QDataStream>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //写文件
    QByteArray array;

    //创建内存文件
    QBuffer memFile(&array);
    memFile.open(QIODevice::WriteOnly);

    memFile.write("111111");
    memFile.write("222222");

    memFile.close();

    qDebug() << memFile.buffer();
    qDebug() << "array" << array;

    QBuffer memFile1;
    memFile1.open(QIODevice::WriteOnly);
    QDataStream stream(&memFile1);
    stream << QString("测试") << 250;
    memFile1.close();

    qDebug() << memFile.buffer();

    //读文件
    memFile1.open(QIODevice::ReadOnly);
    QDataStream stream1;
    stream1.setDevice(&memFile1);
    QString str;
    int a;
    stream1 >> str >> a;
    memFile1.close();

    qDebug() << str.toUtf8().data() << a;
}

Widget::~Widget()
{
    delete ui;
}

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

虚心求知的熊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值