QT学习(19):QIODevice

目录

    • QIODevice类:
      • 一、一般操作
        • 1、open()和close()
        • 2、read()
        • 3、write()
      • 二、随机存取设备和顺序设备
      • 三、读写信号
      • 四、阻塞函数
      • 五、虚函数readData、readLineData、writeData
      • 六、内存缓冲区
      • 七、事务机制
    • QIODevicePrivate类
    • QRingBuffer和QRingChunk

QIODevice类:

QIODevice 为支持读取和写入数据块的设备(如QFile、QBuffer、和QTcpSocket)提供了通用实现和抽象接口。QIODevice 是抽象的,无法实例化,但通常使用它定义的接口来提供与设备无关的 I/O 功能。例如,Qt的XML类在QIODevice指针上运行,允许它们与各种设备(如文件和缓冲区)一起使用。

一、一般操作

在访问设备之前,必须调用open()来设置正确的 OpenMode(例如 ReadOnly 或 ReadWrite)。然后,可以使用write()putChar()写入设备,并通过调用read()readLine()readAll()进行读取。使用完设备后调用close()

1、open()和close()
public:virtual bool open(OpenMode mode);virtual void close();

QIODevice::open()对QIODevicePrivate类d指针的属性数据进行设置。

bool QIODevice::open(OpenMode mode)
{Q_D(QIODevice);d->openMode = mode;d->pos = (mode & Append) ? size() : qint64(0);d->accessMode = QIODevicePrivate::Unset;d->readBuffers.clear();d->writeBuffers.clear();//.............................return true;
}
2、read()
public:qint64 read(char *data, qint64 maxlen);QByteArray read(qint64 maxlen);QByteArray readAll();qint64 readLine(char *data, qint64 maxlen);QByteArray readLine(qint64 maxlen = 0);virtual bool canReadLine() const;

QIODevice类中提供了读写等操作的接口,QIODevicePrivate中保存实际的数据和相关属性、相关操作。几个读取函数最终都调用了qint64 QIODevice::read(char *data, qint64 maxSize)。在内部调用d指针的buffer成员的getchar()或者QIODevicePrivate::read()

qint64 QIODevice::read(char *data, qint64 maxSize)
{Q_D(QIODevice);const bool sequential = d->isSequential();// getChar()的快捷方式,除非我们需要将数据保存在缓冲区中。if (maxSize == 1 && !(sequential && d->transactionStarted)) {while ((chint = d->buffer.getChar()) != -1) {//................................return (qint64(1));}}//....................................const qint64 readBytes = d->read(data, maxSize);return readBytes;
}
public:qint64 peek(char *data, qint64 maxlen);QByteArray peek(qint64 maxlen);qint64 skip(qint64 maxSize);

peek:从设备读取maxlen的字节,而不会产生不好的结果。
skip:从设备跳到maxSize字节。返回实际跳过的字节数。

3、write()
public:qint64 write(const char *data, qint64 len);qint64 write(const char *data);inline qint64 write(const QByteArray &data){ return write(data.constData(), data.size()); }

写操作调用了writeData纯虚函数,同时对d指针的属性成员做相应更改,在windows系统和非windows系统中的处理不同。

qint64 QIODevice::write(const char *data, qint64 maxSize)
{Q_D(QIODevice);//........................................
#ifdef Q_OS_WIN//.................writeData
#endifqint64 written = writeData(data, maxSize);if (!sequential && written > 0) {d->pos += written;d->devicePos += written;d->buffer.skip(written);}return written;
}
public:void ungetChar(char c);bool putChar(char c);bool getChar(char *c);

putChar:将字符c写入设备。调用了QIODevicePrivate::putCharHelper(char),该函数中又会调用QIODevice::write

bool QIODevice::putChar(char c)
{return d_func()->putCharHelper(c);
}
bool QIODevicePrivate::putCharHelper(char c)
{return q_func()->write(&c, 1) == 1;
}

getChar:从设备中读取一个字符并将其存储在c中。调用了QIODevice::read(char *, int)

bool QIODevice::getChar(char *c)
{// readability checked in read()char ch;return (1 == read(c ? c : &ch, 1));
}

ungetChar:将字符c放回设备中,并递减当前位置,除非位置为0。调用此函数通常用于“撤消”getChar()操作。

二、随机存取设备和顺序设备

QIODevice分为两种类型的设备:随机存取设备和顺序设备,可以使用isSequential()来确定设备的类型。

  • 随机存取设备支持使用seek()寻找任意位置。通过调用pos()可以获取文件中的当前位置。QFile和QBuffer都是随机存取设备。
  • 顺序设备不支持搜索任意位置。数据必须一次性读取。函数pos()size()不适用于顺序设备。QTcpSocket和QProcess都是顺序设备。
public:virtual qint64 pos() const;virtual qint64 size() const;virtual bool seek(qint64 pos);virtual bool atEnd() const;virtual bool reset();

seek:对于随机存取设备,此函数将当前位置设置为 pos。

三、读写信号

当有新数据可供读取时,QIODevice 发出readyRead();例如,如果新数据已到达网络,或者如果将其他数据追加到要读取的文件。您可以调用bytesAvailable()来确定当前可用于读取的字节数。在使用异步设备(例如QTcpSocket)进行编程时,通常将bytesAvailable()readyRead()信号一起使用,其中数据片段可以在任意时间点到达。QIODevice 每次将数据有效载荷写入设备时都会发出bytesWritten()信号。使用bytesToWrite()确定当前等待写入的数据量。

Q_SIGNALS:void readyRead();void channelReadyRead(int channel);void bytesWritten(qint64 bytes);void channelBytesWritten(int channel, qint64 bytes);void aboutToClose();void readChannelFinished();

Q_SIGNALS和signals宏的内容一样,都是替换为public

# define Q_SIGNALS public QT_ANNOTATE_ACCESS_SPECIFIER(qt_signal)
# define QT_ANNOTATE_ACCESS_SPECIFIER(x)
public:virtual qint64 bytesAvailable() const;virtual qint64 bytesToWrite() const;

四、阻塞函数

QIODevice 的某些子类(QTcpSocket和QProcess)是异步的。这意味着write()read()等I/O 功能总是立即返回,而当控制返回到事件循环时,可能会与设备本身进行通信。QIODevice提供了一些函数,允许强制立即执行这些操作,同时阻塞调用线程,而无需进入事件循环。这允许在没有事件循环的情况下使用QIODevice子类,或者在单独的线程中使用:

  • waitForReadyRead(),此函数暂停调用线程中的操作,直到有新数据可供读取。
  • waitForBytesWritten(),此函数暂停调用线程中的操作,直到将一个数据有效负载写入设备。
  • waitFor....(),QIODevice的子类为特定于设备的操作实现阻塞功能。例如,QProcess有一个名为waitForStarted()的函数,该函数暂停调用线程中的操作,直到进程启动。
public:virtual bool waitForReadyRead(int msecs);virtual bool waitForBytesWritten(int msecs);

从主 GUI 线程调用这些函数可能会导致用户界面冻结。

五、虚函数readData、readLineData、writeData

通过对 QIODevice 进行子类化,可以为自己的 I/O 设备提供相同的接口。QIODevice 的子类只需要实现受保护的readData()writeData()函数。QIODevice 使用这些函数来实现其所有便利功能,例如getChar()readLine()write()。QIODevice还处理访问控制,因此在调用writeData()可以放心地假设设备以写入模式打开。

protected:virtual qint64 readData(char *data, qint64 maxlen) = 0;virtual qint64 readLineData(char *data, qint64 maxlen);virtual qint64 writeData(const char *data, qint64 len) = 0;

六、内存缓冲区

某些子类(QFile和QTcpSocket)是使用内存缓冲区实现的,用于中间存储数据。这减少了设备访问调用的数量,这些调用通常非常慢。缓冲使getChar()putChar()等函数变得快速,因为它们可以在内存缓冲区上运行,而不是直接在设备本身上运行。但是,某些 I/O 操作不能很好地与缓冲区配合使用。例如,如果多个用户打开同一设备并逐个字符读取它,则当他们打算读取每个单独的块时,他们最终可能会读取相同的数据。出于这个原因,QIODevice 允许通过将 Unbuffered 标志传递给open()来绕过任何缓冲。在对 QIODevice 进行子类化时,请记住在无缓冲模式下打开设备时绕过可能使用的任何缓冲区。

七、事务机制

通常,来自异步设备的传入数据流是碎片化的,数据块可以在任意时间点到达。要处理数据结构的不完整读取,请使用 QIODevice 实现的事务机制。

	void startTransaction();void commitTransaction();void rollbackTransaction();bool isTransactionStarted() const;

startTransaction:在设备上启动新的读取事务,定义读取操作序列中的可还原点。
commitTransaction:完成读取事务。对于顺序设备,事务期间记录在内部缓冲区中的所有数据都将被丢弃。
rollbackTransaction:回滚读取事务。

QIODevicePrivate类

class Q_CORE_EXPORT QIODevicePrivate : public QObjectPrivate
{Q_DECLARE_PUBLIC(QIODevice)
public:QIODevicePrivate();virtual ~QIODevicePrivate();QIODevice::OpenMode openMode;QString errorString;
//...........................................class QRingBufferRef {QRingBuffer *m_buf;//getChar.putChar.size.clear.skip.append.peek...............};QRingBufferRef buffer;QRingBufferRef writeBuffer;qint64 pos;qint64 devicePos;enum AccessMode {//............};mutable AccessMode accessMode;//........函数.......
};

如果允许缓冲且有数据在缓冲区中,直接buffer.read()读取缓冲区数据。如果读取数据小于目标数据,1.readData()直接从设备上读取。2.readData()从设备读取到缓存区,进入下一次循环,继续buffer.read()从缓冲区读取。

qint64 QIODevicePrivate::read(char *data, qint64 maxSize, bool peeking)
{Q_Q(QIODevice);//.............forever {qint64 bufferReadChunkSize = keepDataInBuffer? buffer.peek(data, maxSize, bufferPos): buffer.read(data, maxSize);maxSize -= bufferReadChunkSize;if (maxSize > 0 && !deviceAtEof) {//.............if ((!buffered || maxSize >= readBufferChunkSize) && !keepDataInBuffer) {readFromDevice = q->readData(data, maxSize);//.............} else {readFromDevice = q->readData(buffer.reserve(bytesToBuffer), bytesToBuffer);//.............}//.............}}
}

QRingBuffer和QRingChunk

QRingBuffer是QIODevice用来存储缓冲数据的类,在该类中定义了一个动态数组,在头部读取,尾部追加。
bufferSize为缓冲区存储数据大小,basicBufferSize为可存储数据大小,#define QRINGBUFFER_CHUNKSIZE 4096,在QRingBuffer初始化时会将这个宏赋值给basicBufferSize。

class QRingBuffer
{
public:inline int getChar() {//........}inline void putChar(char c) {char *ptr = reserve(1);//返回地址*ptr = c;}Q_CORE_EXPORT qint64 read(char *data, qint64 maxLength);//..........................
private:QVector<QRingChunk> buffers;qint64 bufferSize;int basicBlockSize;
};

缓冲区读取最终调用函数,先取最大长度和缓冲区数据大小的较小值作为总读取数据长度。每一次循环中取剩余长度和下一块待读取数据长度的较小值作为单次读取数据的长度。memcpy拷贝缓冲数据,拷贝完释放数据,从动态数组buffers中移除。

qint64 QRingBuffer::read(char *data, qint64 maxLength)
{const qint64 bytesToRead = qMin(size(), maxLength);qint64 readSoFar = 0;while (readSoFar < bytesToRead) {const qint64 bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar,nextDataBlockSize());if (data)memcpy(data + readSoFar, readPointer(), bytesToReadFromThisBlock);readSoFar += bytesToReadFromThisBlock;free(bytesToReadFromThisBlock);}return readSoFar;
}

QRingBuffer用来存储数据的QVector<QRingChunk> buffers存储了若干个QRingChunk对象,该类对象就是对QByteArray做简单封装,增加头尾索引值。

class QRingChunk
{
public:void allocate(int alloc);inline const char *data() const{return chunk.constData() + headOffset;}
//...............................
private:QByteArray chunk;int headOffset, tailOffset;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/215838.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安卓.apk的文件app应用程序开发后如何安装运行到真机上测试?

当您完成了一个安卓app的开发之后&#xff0c;进行真机测试是确保应用程序稳定运行的关键步骤之一。下面我们会讲述几种将安卓app安装到手机进行测试的方法&#xff0c;请根据具体情况选择合适的方式。 图片来源&#xff1a;安卓.apk的文件app应用程序开发后如何安装运行到真机…

Scala-初学

前提&#xff0c;已经安装好Scala 在Linux终端 准备资料&#xff1a; a.txt 内容 HIVE 底层 是 hdfs 和 mapreduce 实现存储 和 计算的 。 HIVE 也 可以 使用 hadoop 配置 的 压缩 方法 对 中间 结果 或 最终 数据 进行 压缩 1 import scala.io.Source scala> val lines So…

C++ 指针常量和常量指针的区别

指针常量 指针常量&#xff1a;顾名思义它就是一个常量&#xff0c;但是是指针修饰的。 格式为&#xff1a; int * const p //指针常量在这个例子下定义以下代码&#xff1a; int a&#xff0c;b&#xff1b; int * const p&a //指针常量 //那么分为一下两种操作 *p9;//操…

普通SSL证书和EV SSL证书有什么区别?

SSL证书是一种用于加密网站和保护用户数据传输的安全协议。在SSL证书的类型中&#xff0c;普通SSL证书和EV SSL证书是两种常见的选择。本文将介绍普通SSL证书和EV SSL证书的区别&#xff0c;以及它们在网站安全性和可信度方面的差异。 1、安全性验证程度 普通SSL证书和EV SSL证…

linux(5):linux基础命令第五弹

在linux基础命令第四弹中http://t.csdnimg.cn/tvuNl我们了解了echo、tail命令、管道符和vim文本编辑器的相关内容。这一篇我们会了解关于命令选项的说明 我们在之前的学习中&#xff0c;发现命令中的选项是非常多的&#xff0c;比如-l -c -m -r -w 等等&#xff0c;命令有很多&…

C++学习笔记之五(String类)

C 前言getlinelength, sizec_strappend, inserterasefindsubstrisspace, isdigit 前言 C是兼容C语言的&#xff0c;所以C的字符串自然继承C语言的一切字符串&#xff0c;但它也衍生出属于自己的字符串类&#xff0c;即String类。String更像是一个容器&#xff0c;但它与容器还…

C++入门【6-C++ 修饰符类型】

C 修饰符类型 C 允许在 char、int 和 double 数据类型前放置修饰符。 修饰符是用于改变变量类型的行为的关键字&#xff0c;它更能满足各种情境的需求。 下面列出了数据类型修饰符&#xff1a; signed&#xff1a;表示变量可以存储负数。对于整型变量来说&#xff0c;signe…

12月11日作业

完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示登录成功&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如果账号和密码不匹配&#xff0c;弹…

被迫搬家,宽带迁移怎么办?

广州一栋违建烂尾楼&#xff0c;13年里从未停止出租&#xff0c;年年住满人。这栋楼没有贴外墙&#xff0c;裸露的水泥表面都被雨水腐蚀&#xff0c;很多阳台没有建好&#xff0c;只是简单加装了护栏&#xff0c;存在巨大安全隐患。 为什么烂尾楼年年满人呢&#xff1f; 因为它…

算法:快速幂ksm

为什么使用快速幂&#xff1a; 假设题目要求求a的b次方。 c/c里并没有^运算符&#xff0c;所以我们第一时间可能想到使用for循环&#xff0c;将“a * a”语句循环b次。但是这样时间复杂度为O(n),所以当b过大的时候&#xff0c;我们的程序将会非常慢&#xff0c;所以我们需要使用…

基于ssm乐购游戏商城系统论文

摘 要 随着社会的发展&#xff0c;游戏品种越来越多&#xff0c;计算机的优势和普及使得乐购游戏商城系统的开发成为必需。乐购游戏商城系统主要是借助计算机&#xff0c;通过对信息进行管理。减少管理员的工作&#xff0c;同时也方便广大用户对个人所需信息的及时查询以及管理…

基于深度学习的yolov5入侵检测系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介IntroductionYOLOv5 Overview入侵检测系统架构1. 数据采集2. YOLOv5模型训练3. 实时监测4. 告警与反馈 性能评估与优化 二、功能三、系统四. 总结 一项目简…

Huawei Auth-HTTP Server 1.0 存在任意文件读取漏洞 附POC软件

@[toc] Huawei Auth-HTTP Server 1.0 存在任意文件读取漏洞 附POC 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学…

【精华帖】发布你造的轮子 -- 创建Nuget包(分布操作)

目录 1、您的项目 2、创建 .nuspec 文件 3、一张图片胜过一千个拉取请求 4、包括自述文件 MD 文件 5、构建软件包 6、将包部署到 Nuget.Org

视频中自监督学习:「我的世界」下指令理解与跟随

本文介绍了北京大学人工智能研究院梁一韬助理教授所带领的 CraftJarvis 团队在「我的世界」环境下探索通用智能体设计的新进展&#xff0c;题为“GROOT: Learning to Follow Instructions by Watching Gameplay Videos”。 ​ GROOT 该研究的核心目标是探索能否摆脱文本数据的标…

【NR技术】NR NG-RAN整体架构 -网络接口以及无线协议框架(四)

1 引言 本博文介绍NR NG-RAN的网络节点间的接口以及无线协议框架。网络接口介绍包括RAN和NGC之间的NG接口&#xff1b;无线协议框架包括用户面和控制面协议。 2 NG接口 2.1 NG用户面接口 NG-U (user plane interface)是NG-RAN节点与UPF之间的接口。NG接口的用户平面协议栈如图…

AutoGen实战应用(一):代码生成、执行和调试

AutoGen 是一个支持使用多个代理来开发大型语言模型(LLM) 应用程序的框架&#xff0c;这些代理采样相互对话的方式来解决人类交给的任务。AutoGen 代理是可定制的、可对话的&#xff0c;并且无缝地允许人类参与。他们采用LLM、人类输入和各种工具组合的各种运作模式。 AutoGen …

二分查找25(Leetcode1498满足条件的子序列数目)

代码&#xff1a; 这道题不能用Math.pow 精度不够 得自己写个数组存2的n次方 class Solution {public int numSubseq(int[] nums, int target) {int mod 1000000007;int n nums.length;System.out.println(n);int[] f new int[100005];f[0]1;for(int i1;i<f.length;i){…

docker 安装mysql 主从复制

一、搭建主服务器的mysql 1.1 先新建文件夹 mkdir -p /data/dockerData/mysql-master/conf 1.2 进入/data/dockerData/mysql-master/conf目录下新建my.config, [mysqld] ## 设置server_id&#xff0c;同一局域网中需要唯一 server_id101 ## 指定不需要同步的数据库名称 bin…

论文阅读《High-frequency Stereo Matching Network》

论文地址&#xff1a;https://openaccess.thecvf.com/content/CVPR2023/papers/Zhao_High-Frequency_Stereo_Matching_Network_CVPR_2023_paper.pdf 源码地址&#xff1a; https://github.com/David-Zhao-1997/High-frequency-Stereo-Matching-Network 概述 在立体匹配研究领域…