文章目录
一、QDataStream 二进制文件读写
1. QDataStream 简介
2. QDataStream 实际演示
2.1 QDataStream 读写文件操作
2.2 实现代码——主窗口头文件 widget.h
2.3 实现代码——主窗口源文件 widget.cpp
二、QTextStream 文本文件读写
1. QTextStream 简介
2. QTextStream 实际演示
2.1 QTextStream 读写文件操作
2.2 实现代码——主窗口头文件 widget.h
2.3 实现代码——主窗口源文件 widget.cpp
三、QBuffer
1. QBuffer 简介和操作实现
2. 实现代码——主窗口源文件 widget.cpp
由于每次代码都是在原有程序上修改,因此除了新建项目,不然一般会在学完后统一展示代码。
提示:具体项目创建流程和注意事项见
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 的文件操作当中,有如下的打开方式:
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; }