QTextStream 类(文本流)和 QDataStream 类(数据流)

 

QTextStream 类(文本流)和 QDataStream 类(数据流)Qt 输入输出的两个核心类,其作用分别如下:

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

①、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

QBuffer 类为 QByteArray 提供了一个 QIODevice 接口,以允许使用 QIODevice 接口来访问 QByteArray。默认情况下,创建一个 QBuffer 时,会自动在内部创建一个 QByteArray缓冲区

 

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 等类型的最小长度,未规定最大长度)

QDataStream读写文件 

win.h

#ifndef WIN_H
#define WIN_H

#include <QWidget>
#include <QPushButton>
#include <QFile>
#include <QDataStream>

class Win : public QWidget
{
    Q_OBJECT

public:
    Win(QWidget *parent = nullptr);
    ~Win();

private:
    QPushButton *pb;
    QFile* f;



};
#endif // WIN_H

win.cpp

#include "win.h"

Win::Win(QWidget *parent)
    : QWidget(parent)
{
    this->resize(300,200);
    pb=new QPushButton("AAA",this);
    pb->move(10,10);

    f=new QFile("l.txt");
    f->open(QIODevice::WriteOnly); //以只写方式打开文本l.txt
    QIcon i("l.jpg");
    QPoint p(22,22);
    QDataStream out(f); //创建QDataStream对象并与QFile对象关联
    out <<i<<QString("BBB")<<p; //把对象i,字符串 BBB 和对象p写入文件l.txt中
    //  << 输出符号
    f->close(); //关闭文件

    f->open(QIODevice::ReadOnly); //以只读方式重新打开文本l.txt,以读取其内容
    QIcon i1;
    QString s;
    QPoint p1;

    QDataStream in(f); //创建QDataStream 对象并与 QFile 对象关联
    in>>i1>>s>>p1; //把文件l.txt 的内容读出并存储到i1、s 和 p1 中
    //  >>  输入符号
    //注意,读取数据类型的顺序应与写入时的一致
    pb->setIcon(i1);  //使用从文件读取到的数据设置按钮的图标
    pb->setText(s);
    pb->move(p1);
    f->close();


}

Win::~Win()
{
}

读写原始二进制数据 

可以使用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 必须被预先分配。数据是未编码的。

QFile f("l.txt");

QDataStream out(&f);


f.open(QIODevice::WriteOnly);
    out<<QString("BBB");
    /*以二进制形式写入一个字符串BBB到文件l.txt中,注意:以此种方式写入的字符串BBB是已经编了码的,
      因此实际写入文件的内容并不一定是4字节的大小。*/
    char c[4]="CCC";  //创建缓冲区
    int i1=out.writeRawData(c,4); //把缓冲区c中的4个字节内容写入流中
    //注:因为此函数写入的内容未编码,因此将直接向文件写入一个字符串"ccc"(4字节大小)
    qDebug()<<i1;
    f.close();

    QDataStream in(&f);
    f.open(QIODevice::ReadOnly);
    char *pc=new char[114]; //创建一个缓冲区
    int i2=in.readRawData(pc,114); //从流中读取最多114个字节内容放到缓冲区pc中
    //此时pc中保存的值就是文件l.txt中的原始二进制数据,注意:实际未必会读取114个字节
    qDebug()<<i2; //输出实际读取的字节数
    for(int j=0;j<i2;j++){    //输出全部内容,以循环的方式逐字符输出
        qDebug()<<pc[j];
    }

    f.close();


}
QFile f("l.txt");

 

实例:读取保存自定义类对象

 

readBytes() 和 writeBytes() 

writeBytes()

QDataStream &QDataStream::writeBytes(const char *s, uint len)

先写入一个quint32的数据,该值就是将要写入的数据的长度;紧接着写入相应数据

readBytes()

QDataStream &QDataStream::readBytes(char *&s, uint &l)

先读取一个quint32值,该值就是将要读取的数据的长度,然后读取相应字节的数据到预先定义好的char*中 

注意,readBytes() 不需要我们事先分配好内存

仍然需要程序员自己进行编码和解码的 

QFile f("l.txt");
    f.open(QIODevice::WriteOnly);
    QDataStream out(&f);
    char c[4]="CCC";
    out.writeBytes(c,sizeof(c));  //写入char字符串
    //参数2:写入数据的字节数
    qint32 n=898989;
    QByteArray ba;
    ba.setNum(n);
    out.writeBytes(ba,ba.size());  //写入QByteArray数据
    f.close();

    QDataStream in(&f);
    f.open(QIODevice::ReadOnly);
    char* cc;  //不需要分配内存
    char* dd;
    QByteArray ba1;
    uint nn,mm;
    in.readBytes(cc,nn);  //读取数据
    //读取的数据保存到cc中
    //参数2:返回读取数据的字节数
    in.readBytes(dd,mm);
    qDebug()<<cc<<",   "<<nn;
    qDebug()<<dd<<",   "<<mm;
    f.close();

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 流的总体结构,但也增加了字符占据的空间

写入文件

//QTextStream 虽然能在 Unicode 编码与其他任意编码间进行转换,但并不支持其他任间编码间的转换,因
    //此在使用字符串时,建议使用 QString 类型的字符串,以确保输出的字符串为 Unicode 编码
    QFile f("l.txt");
    QTextStream out(&f);  //创建文本流对象并关联到文件
    f.open(QIODevice::WriteOnly);
    out<<QString("a23b 检说 ui9d 极")<<898989<<"\n";  //写入文本
    //  \n  换行符
    out<<"liming"<<68140318;

    f.close();

读文件 

l.txt文件内容如下:

中国人民万岁 我爱我的祖国 我家在天津

limi ng68140318

我是一位物理教师

QFile f("l.txt");
    QTextStream in(&f);
    f.open(QIODevice::ReadOnly);
    QChar c;
    in>>c; //从l.txt 读取一个字符
    qDebug()<<c;  //输出\u4e2d(这是“中”字的 Unicode 编码)
    //一个汉字一个字符
    bool b=in.seek(0); //把读写指针设置为0,以便从头开始读取
    //成功返回true;否则返回false
    QString s;
    in>>s; //读取一个单词到 s 中(单词由空格分开)
    qDebug()<<s; //输出"中国人民万岁"
    in>>s; //继续读取下一个单词到 s 中
    // >>运算符会自动跳过前导空格,所以读取到的单词前面没有空白符
    qDebug()<<s; //输出"我爱我的祖国"
    in.skipWhiteSpace(); //跳过空白
    //从流中读取并丢弃空白,直到检测到非空格字符,或直到atEnd()返回true。此函数在逐字符读取流时非常有用。
    //空白字符是QChar::isSpace()返回true的所有字符
    s=in.read(10); //读取10个字符,并把读取到的字符保存到s中
    //  \n 是一个字符   一个汉字一个字符
    qDebug()<<s; //输出"我家在天津\nlimi"
    s=in.readLine(); //继续读取余下的整行文本,并把结果保存到 s 中
    //注意:返回的结果中不包含行尾符\n
    qDebug()<<s; //输出"     ng68140318",注意:因为没有跳过空白,所以最前面是空白字符
    in.seek(0);
    s=in.readLine(10); //读取10个字符或整行(本行大于10个字符,因此只读取10个字符), 并把结果保存到s中
    qDebug()<<s;
    in.seek(0);
    s=in.readAll(); //读取整个文本
    qDebug()<<s;  //"中国人民万岁 我爱我的祖国        我家在天津\nlimi     ng68140318\n\n我是一位物理教师"

    //使用循环逐行读取整个文件
    in.seek(0);
    s="";
    while(!in.atEnd()){
        // atEnd()  是否到尾部   是返回true
        s+=in.readLine();
    }
    qDebug()<<s; //"中国人民万岁 我爱我的祖国        我家在天津limi     ng68140318我是一位物理教师"


    f.close();

其它指令

QFile f("l.txt");
    f.open(QIODevice::ReadOnly);
    QTextStream in(&f);

    QTextCodec *tp=in.codec();  //返回当前流的编解码器
    QIODevice *d=in.device();  //返回当前的设备
    //与 &f  相同
    in.setCodec("UTF-8");  //设置编码

    QString s;
    qint64 n;
    s=in.read(9);
    n=in.pos();  //返回当前流读写指针的位置
    QChar qc=in.padChar();//返回当前填充字符
    //' '
    //in.setPadChar()  设置当前填充字符

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

  • 1
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值