文章目录
- 一、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 的文件操作当中,有如下的打开方式:
枚举值 | 描述 |
---|---|
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;
}