QIODevice Class
- 官方文档:https://doc.qt.io/qt-5/qiodevice.html
- QIODevice类是Qt中所有I/O设备的基接口类。
Public Types
flags OpenMode enum OpenModeFlag { NotOpen, ReadOnly, WriteOnly, ReadWrite, Append, …, ExistingOnly } enum QIODevice::OpenModeFlag flags QIODevice::OpenMode
- 与open()一起用于描述打开设备的模式。它也由openMode()返回。
- 某些标志,如Unbuffered和Truncate,在一些子类中使用是没有意义的。
- 其中一些限制是由子类所表示的设备类型所暗示的。
- 在其他情况下,限制可能是由于实现,或者可能是底层平台强加的;
- 例如,QTcpSocket不支持Unbuffered模式,并且本机API中的限制阻止QFile在Windows上支持Unbuffered模式。
- OpenMode类型是QFlags<OpenModeFlag>的类型定义。它存储OpenModeFlag值的OR组合。
- QIODevice为支持读取和写入数据块(如QFile, QBuffer和 QTcpSocket)的设备提供了通用实现和抽象接口。
- QIODevice是抽象的,不能实例化,但是通常使用它定义的接口来提供与设备无关的I/O特性。
- 例如,Qt的XML类操作一个QIODevice指针,允许它们与各种设备(如文件和缓冲区)一起使用。
- 在访问设备之前,必须调用open()来设置正确的OpenMode(例如ReadOnly或ReadWrite)。
- 然后,您可以使用write()或putChar()向设备进行写入,并通过调用read()、readLine()或readAll()进行读取。当你用完这个设备时,调用close()。
- QIODevice区分了两种类型的设备 :随机访问设备和顺序设备。
- 随机访问设备支持使用seek()查找到任意位置。通过调用pos()可以获得文件中的当前位置。QFile和QBuffer是随机访问设备的例子。
- 顺序设备不支持寻找任意位置。数据必须一次读取。函数pos()和size()不适用于顺序设备。QTcpSocket和QProcess是顺序设备的例子。
- 可以使用isSequential()来确定设备的类型。
- 当有新的数据可供读取时,QIODevice发出readyRead(); 例如,如果新的数据已经到达网络上,或者附加的数据被附加到正在读取的文件中。
- 可以调用bytesAvailable()来确定当前可读取的字节数。
- 在使用异步设备(如QTcpSocket)编程时,通常使用bytesAvailable()和readyRead()信号,在异步设备中,数据片段可以到达任意时间点。
- QIODevice在每次将数据有效负载写入设备时发出bytesWritten()信号。使用 bytesToWrite()确定当前等待写入的数据量。
- QIODevice的某些子类,如QTcpSocket和QProcess,是异步的。
- 这意味着像write()或read()这样的I/O函数总是立即返回,而当控制返回到事件循环时,与设备本身的通信可能会发生。
- QIODevice提供的函数允许强制立即执行这些操作,同时阻塞调用线程并且不进入事件循环。这允许在没有事件循环的情况下使用QIODevice的子类,或者在单独的线程中使用:
- waitForReadyRead()——该函数在调用线程中暂停操作,直到有新的数据可供读取。
- waitForBytesWritten()——该函数在调用线程中暂停操作,直到数据的一个有效负载被写入设备。
- waitFor....()——QIODevice的子类为设备特定的操作实现阻塞函数。例如,QProcess有一个名为waitForStarted()的函数,它会暂停调用线程中的操作,直到进程启动。
- 从主GUI线程调用这些函数可能会导致用户界面冻结。例子:
QProcess gzip; gzip.start("gzip", QStringList() << "-c"); if (!gzip.waitForStarted()) return false; gzip.write("uncompressed data"); QByteArray compressed; while (gzip.waitForReadyRead()) compressed += gzip.readAll();
- 通过继承QIODevice的子类,您可以为自己的I/O设备提供相同的接口。
- QIODevice的子类只需要实现受保护的readData()和writeData()函数。
- QIODevice使用这些函数来实现它的所有便利函数,比如getChar()、readLine()和write()。
- QIODevice还为处理访问控制,因此如果调用writeData(),您\可以安全地假设设备是在写模式下打开的。
- 一些子类,如QFile和QTcpSocket,是使用用于中间存储数据的内存缓冲区来实现的。
- 这减少了所需的设备访问呼叫的数量,这通常是非常缓慢的。
- 缓冲使getChar()和putChar()这样的函数速度更快,因为它们可以在内存缓冲区上操作,而不是直接在设备本身上操作。
- 但是,某些I/O操作不能很好地与缓冲区一起工作。例如,如果几个用户打开相同的设备并逐个字符地读取它,他们可能最终会读取相同的数据,而他们本打算读取单独的块。
- 出于这个原因,QIODevice允许通过将Unbuffered标志传递给open()来绕过任何缓冲。当继承QIODevice的子类时,请记得在设备以Unbuffered模式打开时绕过任何可能使用的缓冲区。
- 通常,来自异步设备的传入数据流是分段的,数据块可以到达任意时间点。要处理数据结构的不完整读取,可以使用QIODevice实现的事务机制。有关详细信息,请参阅startTransaction()和相关函数。
- 一些顺序设备支持通过多个通道进行通信。
- 这些通道表示具有独立排序传递属性的独立数据流。
- 一旦设备被打开,可以通过调用readChannelCount()和writeChannelCount()函数来确定通道的数量。
- 要在通道之间切换,分别调用setCurrentReadChannel()和setCurrentWriteChannel()。
- QIODevice还提供了额外的信号来处理每个通道的异步通信。
- 参考:QBuffer, QFile, 和QTcpSocket.