QT学习:10 IO类
title: framework-cpp-qt-10-IO类
EntryName: framework-cpp-qt-10-QIODevice
date: 2020-04-17 10:24:06
categories:
tags:
- qt
- c/c++
---
章节描述:
QIODevice类是所有输入输出IO类的基础类,为IO类提供了统一的调用接口(因此我们称QIODevice类以及其派生类为IO类)。
QIODevice 是一个抽象类,所以不能被实例化,但通常会用到它定义的接口,这些接口提供设备无关的I/O特性。例如Qt的XML类通过操作一个QIODevice 的指针,可以使用各种各样的设备(files,buffers等)。
IO设备类型
IO类支持随机存储,和顺序储存设备。
可以使用
isSequential()
判断设备是否是顺序设备。其中顺序设备不支持
pos()
,size()
方法。调用
size()
函数时,如果是随机设备则返回当前设备的大小,如果是顺序设备则返回bytesAvailable()
。在设备关闭的情况下调用size()
函数将不会反映设备的实际大小,因此调用该函数前保证设备已打开。
顺序存取设备:只能从头开始顺序读写数据,不能指定数据的读写位置。顺序设备没有位置概念,也不支持搜索,只能在数据可用时一次性读取所有数据。典型的顺序设备是Socket
随机存取设备:随机设备就是文件,它们具有大小和当前位置,支持在数据流中向前向后搜索,可以定位到任意位置进行数据的读写。
QT中IO设备的继承类图:
QIODevice
│ 随机设备
├── QBuffer
├── QFileDevice
│ ├── QFile
│ │ └── QTemporaryFile
│ └── QSaveFile
│
│ 顺序设备
├── QAbstractSocket
│ ├── QTcpSocket
│ │ ├── QSctpSocket
│ │ └── QSslSocket
│ └── QUdpSocket
└── QProcess
IO类继承于QIODevice类,只需要实现自己的writeData()
和readData()
方法。其他读写方法QIODevice都是调用writeData()
和readData()
实现的。
操作流程
在访问设备之前,必须先调用open()
,并设置正确的OpenMode(such as ReadOnly or ReadWrite)
。你可以用write()
,putChar()
来写入设备。也可以用read()
,readLine()
来读设备。使用完毕后调用close()
。
在访问IO类,必须先调用open()
方法打开设备,之后才能调用读写方法对类进行操作。结束操作后需要调用close()
方法关闭设备。
调度 与 同步
IO类发射readyRead()
信号表示有数据可以读取,对应的可以调用bytesAvailable()
方法了解可以读取多少字节的数据。
同理,发射bytesWritten()
信号表示数据写入完成,对应的可以调用bytesToWrite()
方法了解写入了多少字节的数据。
IO类的读写函数是非阻塞的,调用方法后不会等待数据读写完成方法,而是立即返回。
QTcpSocket and QProcess是QIODevice的子类,是异步的,这意味着 I/O 函数
write()
orread()
的结果总是立即返回,然而,当控件返回到事件循环时,可能会发生与设备本身的通信。
因此QIODevice提供函数在阻塞调用线程和不输入事件循环的同时,允许程序立即执行,这使得QIODevice的子类可以被使用,在没有循环事件或者是单线程的条件下,提供了waitForReadyRead()
和 waitForBytesWriten()
方法实现阻塞(在调用读写方法后调用对应的wait…
方法实现阻塞)
waitFor...():子类会实现相应的函数为了特殊的操作。
比如QProcess 有个叫waitForStarted()的函数。它将会延迟调用的线程,直到那个process已经启动。
QProcess gzip;
gzip.start("gzip", QStringList() << "-c");
if (!gzip.waitForStarted())
return false; gzip.write("uncompressed data"); QByteArray compressed;
while (gzip.waitForReadyRead())
compressed += gzip.readAll();
IO类例如QFile,QTcpSocket提供了buffer机制,用于减少底层驱动系统调用,提高访问速度。特别是提高了getChar,putChar方法的速度 。但是在多对象需要读取同一个设备的大批量数据时,buffer会导致内存中存在多个同样的数据副本,内存开销巨大。这个情况,可以 在调用open()方法时设置Unbuffered模式关闭buffer机制。
常用操作
open(OpenMode mode):打开设备。mode参数用于设置读写模式,buffer机制,读写机制等。
close():关闭设备
isOpen():判断设备是否被打开。
isWriteable:判断设备是否支持写入模式。(Open方法设置的)
isReadable:判断设备是否支持读取。
isSequential():判断设备是否是顺序设备
isTextModeEnable():Text模式getChar方法将忽略’/r’换行符,返回下个字符。
setTextModeEnable():设置text模式
打开文件
bool QIODevice::open(QIODevice::OpenMode mode)
描述:以指定的方式打开一个文件。
参数解析:
mode:打开方式
QIODevice::NotOpen
不打开QIODevice::ReadOnly
以只读的方式打开.QIODevice::WriteOnly
以只写的方式打开,该模式意味着Truncate,除非与ReadOnly,Append或NewOnly结合使用。QIODevice::ReadWrite
设备以读写的方式打开,写入文件会覆盖之前的内容(打开文件期间多次写入不会覆盖)。QIODevice::Append
以追加模式打开,以便将所有数据写入文件末尾,此模式下不能读文件。QIODevice::Truncate
如果可能,删除文件原有内容。QIODevice::Text
读取时,行尾终止符被转换为'\ n'。 写入时,行尾终止符将转换为本地编码,例如Win32的“\ r \ n”。(常用于文本文件以行为单位的读取)QIODevice::Unbuffered
无缓冲的形式打开,设备中的任何缓冲都会被跳过。NewOnly
:只允许打开一个不存在的文件ExistingOnly
:只允许打开一个已经存在的文件
设置
调用openMode()
函数可以获取当前设备的打开模式。如果在设备打开的情况下改变设备模式,可以调用setOpenMode()
函数来更改。
调用setTextModelEnabled()
函数可以设置设备模式为Text,这对于自定义处理终止符非常有帮助。调用isTextmodeEnabled()
函数可以确定设备模式是否有Text。
读取
读取数据前必须先判断是否有数据可读,有两种方法来确定是否可以读取数据:
调用
isReadable()
函数;接收到
readyRead()
信号。(当有新数据可被读取时会发出该信号)
通常采用信号的方式,然后调用
bytesAvailable()
函数来确定可读取数据的大小,通常与顺序设备一起使用,来确定缓冲区中分配的字节数。
调用read()
函数来读取数据,无法读取时返回-1。
便捷函数有readAll()
、readLine()
/canReadLine()
、getChar()
/ungetChar()
。
写入
调用isWritable()
函数可以判断设备是否设置打开模式中包含了WriteOnly标志,这是一个便捷函数。
写入数据时,一般会先写入缓冲区,然后再从缓冲区写入设备。调用bytesToWrite()
函数返回即将写入设备的数据大小,而对于无缓冲的设备则返回0。每次写入设备数据时都会发出bytesWritten()
信号。
写入数据到设备中,调用write()
函数:
qint64 QIODevice::write(const char *data)
qint64 QIODevice::write(const QByteArray &byteArray)
qint64 QIODevice::write(const char *data, qint64 maxSize)
便捷函数有putChar()
函数。
读写位置
对于随机设备来说,每次读写都会导致内部的文件指针偏移;只有随机设备才可以设置/读取读写位置。
bool QIODevice::seek(qint64 pos) //定位文件指针。
qint64 QIODevice::pos() const // 获取文件指针位置
事务机制
事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据项的一个程序执行单元(unit)。事务一般由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。
为什么要事务?
事务是为解决数据安全操作提出的,事务控制实际上就是控制数据的安全访问。
用一个简单例子说明:银行转帐业务,账户A要将自己账户上的1000元转到B账户下面,A账户余额首先要减去1000元,然后B账户要增加1000元。假如在中间网络出现了问题,A账户减去1000元已经结束,B因为网络中断而操作失败,那么整个业务失败,必须做出控制,要求A账户转帐业务撤销。这才能保证业务的正确性,完成这个操走就需要事务,将A账户资金减少和B账户资金增加放到同一个事务里,要么全部执行成功,要么全部撤销,这样就保证了数据的安全性。
事务的4个特性(ACID):
原子性(atomicity):事务是数据库的逻辑工作单位,而且是必须是原子工作单位,对于其数据修改,要么全部执行,要么全部不执行。
一致性(consistency):事务在完成时,必须是所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。(实例:转账,两个账户余额相加,值不变。)
隔离性(isolation):一个事务的执行不能被其他事务所影响。
持久性(durability):一个事务一旦提交,事物的操作便永久性的保存在DB中。即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
一般来说,异步设备的输入流是分段的,数据块可以在任意的时间内到达。要在这种情况下读到完整数据,使用QIODevice的事务机制。
读取设备中的数据时,我们可以调用startTransaction()
函数来在读取操作序列中设置一个恢复点。接下来的代码进行一般的读取操作,然后调用commitTransaction()
函数来提交所有的操作。例如:
in.startTransaction();
QString nextFortune;
in >> nextFortune;
if (!in.commitTransaction())
return;
调用rollbackTransaction()
函数来回滚事务,这会将来自源的输入流恢复到startTransaction()
时的点。
读写通道
一些顺序设备支持多通道通信,这些通道代表了具有独立排序传递特性的独立数据流。打开设备后,调用readChannelCount()
、writeChannelCount()
函数来确定通道数。调用setCurrentReadChannel()
、setCurrentWriteChannel()
函数来切换通道。
此外,QIODevice还提供额外的信号来处理通道的异步通信。
如果通道有新数据可被设备读取时,发出
channelReadyRead()
信号。如果通道有数据写入设备时,发出
channelBytesWritten()
信号。关闭读取通道禁止输入流时,会发出
readChannelFinished()
信号。
错误信息
当设备发生故障时,我们可以调用setErrorString()函数来给设备设置一个错误信息,任何时候都可以调用errorString()
函数来查看当前设备的错误信息。
QT学习:10 IO类的更多相关文章
- QT学习之常用类的总结
QApplication 应用程序类 管理图形用户界面应用程序的控制流和主要设置 QPalate QLabel 标签类 提供文本或者图像的显示 QPushButton 按钮类 提供 ...
- QT学习之QPair类
#QPair类 QPair是一个用来存储一对对象的容器模板.其有两个值,first和second. QPair() QPair(const T1 & value1, const T2 & ...
- Qt 学习之路 2(10):对象模型
Home / Qt 学习之路 2 / Qt 学习之路 2(10):对象模型 Qt 学习之路 2(10):对象模型 豆子 2012年9月2日 Qt 学习之路 2 45条评论 标准 C++ 对象模 ...
- Java程序猿的JavaScript学习笔记(10—— jQuery-在“类”层面扩展)
计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...
- Qt 学习之路 2(73):Qt 线程相关类
Home / Qt 学习之路 2 / Qt 学习之路 2(73):Qt 线程相关类 Qt 学习之路 2(73):Qt 线程相关类 豆子 2013年11月26日 Qt 学习之路 2 7条评论 希 ...
- QT学习之文件系统读写类
#QT学习之文件系统读写类 QIODevice QFileDevice QBuffer QProcess 和 QProcessEnvironment QFileDevice QFile QFileIn ...
- 系统学习 Java IO (十六)----这么多类,应该用哪个?
目录:系统学习 Java IO---- 目录,概览 Java IO目的和功能 Java IO 包含 InputStream,OutputStream,Reader 和 Writer 类的许多子类. 原 ...
- iOS学习10之OC类和对象
本次是OC的第一节课,主要是学习和理解类与对象 1.面向对象 1> OOP(Object Oriented Programming)面向对象编程. 面向对象以事物为中心,完成某件事情都需要哪些事 ...
- Qt 学习之路 :Qt 线程相关类
希望上一章有关事件循环的内容还没有把你绕晕.本章将重新回到有关线程的相关内容上面来.在前面的章节我们了解了有关QThread类的简单使用.不过,Qt 提供的有关线程的类可不那么简单,否则的话我们也没必 ...
- QT学习之第一个程序
QT学习之第一个程序 目录 手动创建主窗口 居中显示 添加窗口图标 显示提示文本 Message Box的应用 手动连接信号与槽 手动创建主窗口 窗口类型 QMainWindow: 可以包含菜单栏.工 ...
随机推荐
- 低开开发笔记(五):修bug-深拷贝与浅拷贝
好家伙 今天遇到一个bug 0.问题描述 描述如下: 代码如下: copynodefunc() { this.copynode = this.model.selected }, affixnod ...
- vue+element设置选择日期最大范围(优秀版)
element的选择日期组件里没有像移动端vant直接设置max-date的api,因此在不能动态设置选择的第二个时间(需要分别选择起止时间和结束时间,但可以加上关联), 看了很多博客有的效果直接出不 ...
- 一个完整的可以输出移动端当前省市(地理坐标)的html页面
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- pikachu靶机练习平台-xss
第一题:反射性xss(get) 输出的字符出现在url中 第二题:反射性xss(post) 登录后输入<script>alert(1)</script> 第三题:存储型xss ...
- 03 Xpath lxml库的安装和使用
Python lxml库的安装和使用 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 Xpath 表达式提供了良好的支持,因此能够了高效地解析 HTML/XML 文 ...
- 在Docker内部使用gdb调试器报错-Operation not permitted
在docker内部使用gdb调试时刻遇到了gdb如下报错信息: warning: Error disabling address space randomization: Operation not ...
- C 语言编程 — GDB 调试工具
目录 文章目录 目录 前文列表 代码调试 GDB 启动 GDB 交互命令 运行程序 暂停程序 设置断点 设置观察点 设置捕捉点 打印信息 查询运行信息 分割窗口 前文列表 <程序编译流程与 GC ...
- 『手撕Vue-CLI』处理不同指令
前言 在上一篇『手撕Vue-CLI』添加自定义指令中,已经实现了自定义指令的添加,但是指令还是比较简单的,只是简单的打印一句话,那么在实际运用场景中,可能会有更多的需求,比如可能需要在指令中传递参数, ...
- MyBatis延迟加载策略详解
延迟加载就是在需要用到数据的时候才进行加载,不需要用到数据的时候就不加载数据.延迟加载也称为懒加载. 优点:在使用关联对象时,才从数据库中查询关联数据,大大降低数据库不必要开销. 缺点:因为只有当需要 ...
- 平衡二叉树(AVL)插入结点后的再平衡思路
理解平衡二叉树 在解决平衡二叉树动平衡问题,我们先来明确什么是平衡二叉树: 平衡二叉树是二叉搜索树的一种特殊情况,所以在二叉搜索树的基础上加上了如下定义: 平衡因子:我们将二叉树中各个结点的左右子树的 ...