1 概述
-
QTextStream
和QDataStream
都是对流进行操作
-
QTextStream
只能普通类型的流操作像QChar、QString、int
…,其实就很类似我们c或者c++中读写文件的感觉, -
QDataStream
就厉害了,无论是QTextStream
的普通类型的流操作还是一些特殊类型的流操作它都可以办的到比如:QFont
、QPoint
、QDate
之类的几乎所有Qt中支持的所有类型都可以用QDataStream
来进行操作。
-
QTextStream
类(文本流
)和QDataStream
类(数据流
)Qt 输入输出的两个核心类
,其作用分别如下: -
①、
QTextStream
类:用于对数据进行文本格式的读/写操作,可在 QString、QIODevice或 QByteArray 上运行,比如把数据输出到 QString、QIODevice 或 QByteArray 对象上,或进行相反的操作。 -
②、
QDataStream
类:用于对数据进行二进制
格式的读/写操作,QDataStream 只可在QIODevice 或 QByteArray 上运行,因为 QString 只存放字符数据 -
QIODevice 类是 Qt 中所有 I/O 设备的基础接口类(这是一个抽象类),也就是说 QIODevice及其子类描述的是 I/O 设备,该类为支持读/写数据块的设备提供了通用实现和抽象接口,比如 QFile、QBuffer、QTcpSocket 等
-
QIODevice
把设备分为两类:随机存储设备和顺序存储设备 -
①、随机存储设备:可定位到任意位置(使用 seek()函数),随机存储设备有 QFile,QTemporaryFile,QBuffer
-
②、顺序存储设备:不支持任意的位置存储,顺序存储设备有 QProcess、QTcpSocket、QUdpSocket 和 QSslSocket
1.1 QTextStream 类(文本流)
-
字节顺序标记 BOM(Byte Order Mark):BOM 是出现在文本文件头部的一种用于标识文件格式的编码,UTF-16 和 UTF-32 通常使用 BOM 来表示文本的字节序,字节序对 UTF-8没有意义,因此 UTF-8 不需要使用 BOM 来表明字节序,但可使用 BOM 来表明其编码方式,通常使用 0xEF BB BF 来表明此文本是使用的 UTF-8 编码。UTF-8 不推荐使用无意义的 BOM,但很多程序在保存 UTF-8 编码的文件时仍然带有 BOM(即在文件的开头加上 0xEF BB BF 三个字节),比如 windows 的记事本等,因此在编辑 UTF-8 的文件时,需要注意该文件是否带有 BOM 的问题
-
QString
存储一个 16 位的 QChar 字符串,其中每个 QChar 对应一个 Unicode4.0 字符(即存储的字符含有16位),对于代码值超过65536的Unicode字符使用两个连续的QChar表示。QByteArray 类用于存储原始字节和传统的 8 位以’\0’终止的字符串。Qt 内部大量使用了QString,因此通常应使用 QString,QByteArrayy 主要用于存储原始二进制数据 -
QTextStream
类用于对数据进行文本格式的读/写操作
,可在 QString、QIODevice 或QByteArray 上运行,使用 QTextStream 可方便的读/写单词、行和数字,另外 QTextStream还对字段填充、对齐和数字格式提供了格式选项的提供支持 -
QTextStream
在其内部使用 16 位(两字节)长的 QChar 类型存放每个字符,字符集使用Unicode,这与 C++的 iostream 不同,iostream 每个字符的类型由模板参数 charT 指定,标准库已将其特化为 char 和 wchar_t 类型,除此之外还可为 charT 指定其他类型,而QTextStream 的字符类型固定为 QChar 类型,使用此种方式简化了 Qt 流的总体结构,但也增加了字符占据的空间
1.2 QDataStream 类
- 字节序:即多字节数据(即大于一个字节的数据)在内存中的存储顺序,有如下两种方式
Little-Endian(LE,小端)
:即低位字节存储在低地址端,高位字节存储在高地址端
Big-Endian(BE,大端)
:即高位字节存储在低地址端,低位字节储倣在高地址端。这是 QDataStream 的默认字节序。
-
比如对于整数 0x2345,若按 big-endian(大端)顺序存储,则按 0x23、0x45 的顺序存储,若按 little-endian(小端)顺序存储,则以 0x45、0x23 的顺序存储
-
QDataStream 实现了基本的 C++数据类型的序列化,比如 char,short,int,char *等。更复杂的数据类型的序列化是通过分解原始单元来完成的
-
QDataStream 支持的 Qt 类型有 QBrush、QColor、QDateTime、QFont、QPixmap、QString、QVariant 等类型,还包括容器类型,比如 QList、QVector、QSet、QMap 等
-
对于整数,建议始终转换为 Qt 整数类型(比如 qint32 等)进入写入,并将其读入为相同的Qt整数类型,这样可以确保获取确定的大小的整数,以避免编译器和平台差异的影响(注:C++语法只规定了 int,short 等类型的最小长度,未规定最大长度)
1.2.1 读写原始二进制数据
-
可以使用int readRawData(char s, int len)将数据读入一个预先分配好的char; 缓冲区 s 必须被预先分配,缓冲区 s 使用 new[]分配,使用 delete 操作符销毁
-
可以使用int writeRawData(const char *s, int len)函数把原始数据写入datastream 使用这种方式的话,要由你自己进行所有数据的编码和解码
int writeRawData(const char *s, int len);
- 把 len 个字节的数据从缓冲区 s 写入流,并返回实际写入的字节数,若发生错误,则返回-1,注意:数据未编码
int readRawData(char *s, int len);
- 从流中读取最多 len 个字节到缓冲区 s 中,并返回读取的字节数,若产生错误,则返回−1,缓冲区 s 必须被预先分配。数据是未编码的。
1.2.2 readBytes() 和 writeBytes()
QDataStream &QDataStream::writeBytes(const char *s, uint len)
- 先写入一个quint32的数据,该值就是将要写入的数据的长度;紧接着写入相应数据
QDataStream &QDataStream::readBytes(char *&s, uint &l)
-
先读取一个quint32值,该值就是将要读取的数据的长度,然后读取相应字节的数据到预先定义好的char*中 。
-
注意,readBytes() 不需要我们事先分配好内存,仍然需要程序员自己进行编码和解码的
2 QTextStream示例代码
//
// 任务执行
virtual void exec()
{
QFile file(m_filePath + "/" + "log.csv");
if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append))
{
return;
}
// 设置编码格式为 GB2312
QTextCodec::setCodecForLocale(QTextCodec::codecForName("GB2312"));
QTextStream dataStream(&file);
dataStream << m_strHeader<< "\n";
for (auto it:m_vecAllRecord)
{
dataStream << QString("%1,%2,%3,%4").arg(it.logTime).arg(it.strUserNumber).arg(it.strOperateType).arg(it.strDetailInfo) << "\n";
}
file.close();
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
}
3 QDataStream示例代码
//写文件
QFile file("test.bat");
if(file.open(QIODevice::WriteOnly|QIODevice::Truncate)){
QDataStream out(&file);
int age=18;
out<<QString("test")
<<QDate::fromString("2023-05-10","yyyy-MM-dd")
<<age;
file.close();
}else{
file.errorString();
}
//读文件
if(file.open(QIODevice::ReadOnly)){
QDataStream in(&file);
QString name;
QDate birth;
int age;
in>>name>>birth>>age;
qDebug()<<"姓名:"<<name
<<"出生日期:"<<birth
<<"年龄:"<<age;
}else{
qDebug()<<file.errorString();
}