Qt SerialPort 與 PyQt5 (三)

本文用于介紹 QIODevice 類,該類是 QSerialPort 的父類。
系統(tǒng)環(huán)境:Win10 64位
轉(zhuǎn)載請(qǐng)注明出處:http://www.itdecent.cn/u/5e6f798c903a

4.QIODevice 類

官方文檔
Header: #include <QSerialPort>
qmake: QT += core
Inherits: QObject
Inherited By: QAbstractSocket, QBluetoothSocket, QBuffer, QFileDevice, QLocalSocket, QNetworkReply, QProcess, and QSerialPort

為了便于理解,這里給出本節(jié)內(nèi)容的思維導(dǎo)圖:( 本節(jié)后面的內(nèi)容也遵循此結(jié)構(gòu) )


QIODevice.png

4.1 簡(jiǎn)介

QIODevice 類是 Qt 中所有 I/O 設(shè)備的基礎(chǔ)接口類。
QIODevice 為支持?jǐn)?shù)據(jù)塊讀寫的設(shè)備 (如:QFile, QBufferQTcpSocket) 提供了通用實(shí)現(xiàn)和抽象接口。
QIODevice 屬于抽象類,不能被實(shí)例化,但通常會(huì)使用由 QIODevice 定義的接口來提供設(shè)備共有的 I/O 特性。例如,Qt 的 XML 類運(yùn)行在 QIODevice 指針上,以允許 XML 類可與各種設(shè)備( 如文件和緩存 )一同被使用。

在訪問設(shè)備之前,必須調(diào)用 open() 函數(shù),以設(shè)置正確的 OpenMode (如 ReadOnlyReadWrite)。然后,可以調(diào)用 write() 或 putChar() 進(jìn)行寫入,或調(diào)用 read()、readLine()、readAll() 進(jìn)行讀取。完成操作后,調(diào)用 close() 關(guān)閉設(shè)備。

QIODevice 可識(shí)別兩種設(shè)備類型(可調(diào)用 isSequential() 來確定設(shè)備的類型):

  1. 隨機(jī)訪問設(shè)備( random-access devices ),支持使用 seek() 來查找任意位置。通過調(diào)用 pos(),可獲得在文件中的當(dāng)前位置。QFile 和 QBuffer 便屬于這類設(shè)備。
  2. 順序設(shè)備( sequential devices ),不支持查找任意位置。數(shù)據(jù)必須被一次性讀取。函數(shù) pos() and size() 不適用于順序設(shè)備。 QTcpSocket and QProcess 便屬于這類設(shè)備。

當(dāng)有可供讀取的新數(shù)據(jù)時(shí),QIODevice 會(huì)發(fā)出 readyRead() 信號(hào)(比如,網(wǎng)絡(luò)上有新數(shù)據(jù)抵達(dá)時(shí),或是有新數(shù)據(jù)被追加到正在讀取的文件時(shí))。bytesAvailable() 用于確定當(dāng)前可供讀取的字節(jié)數(shù)。為異步設(shè)備(如 QTcpSocket )編寫程序時(shí),通常會(huì)同時(shí)使用 bytesAvailable() 和 readyRead() ,因?yàn)楫惒皆O(shè)備的數(shù)據(jù)片段可能會(huì)在任意時(shí)間點(diǎn)到達(dá)。每當(dāng)數(shù)據(jù)載荷被寫入設(shè)備時(shí),QIODevice 便會(huì)發(fā)射 bytesWritten() 信號(hào)。bytesToWrite() 用于確定當(dāng)前等待寫入的數(shù)據(jù)總量。

QIODevice 的某些子類屬于異步子類,比如 QTcpSocketQProcess 。這些子類的 I/O 函數(shù)(如 write() 、read() )總是立即返回,等控制權(quán)返回事件循環(huán)后,才會(huì)和設(shè)備本身進(jìn)行通訊。QIODevice 還提供了相應(yīng)的函數(shù),以便強(qiáng)制 I/O 操作被立即執(zhí)行,同時(shí)會(huì)阻塞調(diào)用線程,而不會(huì)進(jìn)入事件循環(huán)。以下函數(shù)便具有這樣的特性,但不要在事件循環(huán)中使用它們,或是在另外一個(gè)單獨(dú)的線程中使用。

  1. waitForReadyRead() - 該函數(shù)會(huì)在調(diào)用線程中掛起操作,直到有可供讀取的新數(shù)據(jù)為止。
  2. waitForBytesWritten() - 該函數(shù)在調(diào)用線程中掛起操作,直到一個(gè)數(shù)據(jù)載荷被寫入到設(shè)備為止。
  3. waitFor....() - 在 QIODevice 的子類中,針對(duì)設(shè)備特有的操作實(shí)現(xiàn)的阻塞函數(shù)。例如,例如, QProcess 有一個(gè)叫做 waitForStarted() 的函數(shù),可在調(diào)用線程中掛起操作直到進(jìn)程啟動(dòng)。

在主線程或 GUI 線程中調(diào)用以上函數(shù),可能會(huì)導(dǎo)致用戶界面凍結(jié)。例如:

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 設(shè)備提供相同的接口。QIODevice 的子類僅需要實(shí)現(xiàn)受保護(hù)的 readData() 和 writeData() 函數(shù)。QIODevice 使用這兩個(gè)函數(shù)來實(shí)現(xiàn)相關(guān)函數(shù)(如, getChar()、readLine() 和 write()),使操作更加便捷。QIODevice 還會(huì)為我們處理訪問控制,因此如果調(diào)用了 writeDate(),則可以安全地假定設(shè)備以寫模式打開。

QFileQTcpSocket 這樣的子類,會(huì)使用內(nèi)存緩沖區(qū)來實(shí)現(xiàn)中間數(shù)據(jù)的存儲(chǔ)。這種方式減少了訪問設(shè)備( 這里的設(shè)備指 file、socket 等 )的次數(shù),但這種方式通常非常慢。使用 getChar() 和 putChar() 這樣的函數(shù)訪問緩沖區(qū),會(huì)更加快捷。因?yàn)檫@些函數(shù)在內(nèi)存緩沖區(qū)中運(yùn)行,而非直接運(yùn)行在設(shè)備中。但是,某些 I/O 操作對(duì)緩沖區(qū)不起作用,例如:如果多個(gè)用戶都打開了相同的設(shè)備并逐一讀取每個(gè)字符,那么當(dāng)用戶打算讀取各自所需的數(shù)據(jù)塊時(shí),它們最終可能會(huì)讀取到相同的數(shù)據(jù)。出于此原因,QIODevice 允許允許向 open() 函數(shù)傳遞 Unbuffered 標(biāo)志來忽略任何緩沖。在創(chuàng)建 QIODevice 的子類時(shí),當(dāng)設(shè)備在 Unbuffered 模式下被打開后,記得忽略任何緩沖區(qū)。

通常情況下,來自異步設(shè)備的數(shù)據(jù)流是片段華的,數(shù)據(jù)塊可能會(huì)在任意時(shí)間點(diǎn)到達(dá)。要處理讀取到的不完整的數(shù)據(jù)結(jié)構(gòu),可使用由 QIODevice 實(shí)現(xiàn)的事務(wù)處理機(jī)制。詳細(xì)信息,請(qǐng)參閱 startTransaction() 及相關(guān)函數(shù)。

某些順序設(shè)備支持通過多通道通訊。通道代表獨(dú)立的數(shù)據(jù)流,擁有相互獨(dú)立的發(fā)送順序。一旦相應(yīng)設(shè)備被打開,便可通過調(diào)用 readChannelCount() 和 writeChannelCount() 函數(shù)來確定通道的數(shù)量。需要切換通道時(shí),請(qǐng)分別調(diào)用 setCurrentReadChannel() 和 setCurrentWriteChannel()。QIODevice 還提供了額外的信號(hào),用于處理基于每個(gè)通道的異步通訊。

4.2 創(chuàng)建對(duì)象

  • QIODevice::QIODevice()
    構(gòu)建一個(gè) QIODevice 對(duì)象。
  • QIODevice::QIODevice(QObject *parent)
    使用給定的父對(duì)象構(gòu)建一個(gè) QIODevice 對(duì)象。
  • QIODevice::~QIODevice() [virtual]
    該析構(gòu)函數(shù)是虛擬的,QIODevice 屬于抽象基類。該析構(gòu)函數(shù)不會(huì)調(diào)用 close(),但是其子類的析構(gòu)函數(shù)可能會(huì)調(diào)用。如果有疑慮,請(qǐng)?jiān)阡N毀 QIODevice 前調(diào)用 close()。

4.3 打開模式

enum QIODevice::OpenModeFlag 枚舉配合 open() 函數(shù)使用,用于描述設(shè)備的打開方式??捎猛ㄟ^ openMode() 函數(shù)可查看設(shè)備的打開模式。

Constant Value Description
QIODevice::NotOpen 0x0000 設(shè)備沒有被打開
QIODevice::ReadOnly 0x0001 以讀模式被打開
QIODevice::WriteOnly 0x0002 以寫模式被打開,該模式意味著截?cái)?/td>
QIODevice::ReadWrite ReadOnly WriteOnly 以讀/寫模式打開
QIODevice::Append 0x0004 以追加模式打開設(shè)備,所有數(shù)據(jù)會(huì)被追加到文件的末尾。
QIODevice::Truncate 0x0008 如果可能的話,設(shè)備會(huì)在被打開之前截?cái)唷?調(diào)用 open() 函數(shù)之前的內(nèi)容,都會(huì)丟失。
QIODevice::Text 0x0010 在讀取時(shí),行終止符被轉(zhuǎn)換為 \n 。在寫入時(shí),行終止符被轉(zhuǎn)換為平臺(tái)相關(guān)的本地編碼。比如 Win32 對(duì)應(yīng) \r\n
QIODevice::Unbuffered 0x0020 設(shè)備中的任何緩沖區(qū)都將被忽略。

因?yàn)樽宇惐硎镜脑O(shè)備類型會(huì)隱含某些限制條件。所以某些標(biāo)志 ( 如 UnbufferedTruncate ) 配合某些子類使用時(shí),可能沒有實(shí)際意義。有些情況下,實(shí)現(xiàn)方式也會(huì)導(dǎo)致一些限制,另外底層平臺(tái)也會(huì)施加一些限制。例如,QTcpSocket 不支持 Unbuffered 模式;另外在 Windows 中由于本地 API 的限制,使得 QFile 不支持 Unbuffered模式。

flags QIODevice::OpenMode 是由 QFlags<PinoutSignal> 定義的類型。該類型可使用 OR 運(yùn)算對(duì) OpenMode 中的值進(jìn)行組合。

  • void QIODevice::setOpenMode(OpenMode openMode) [protected]
    將設(shè)備的打開方式設(shè)置為 openMode 。
    如果需要在設(shè)備被打開后改變其打開方式,可調(diào)用該函數(shù)進(jìn)行設(shè)置。

  • OpenMode QIODevice::openMode() const
    返回已打開的設(shè)備的打開方式,比如:ReadOnly 或 WriteOnly。

  • bool QIODevice::isTextModeEnabled() const
    如果打開模式中開啟了 Text 標(biāo)記,便會(huì)返回 true ;否則返回 false 。

  • void QIODevice::setTextModeEnabled(bool enabled)
    假如 enabled 的值為 true ,則會(huì)在設(shè)備的打開模式中添加 Text 標(biāo)記;如果 enable 的值為 false ,則會(huì)從打開模式中移除 Text 標(biāo)記。該特性對(duì)于在 QIODevice 上提供具備自定義行尾處理功能的類非常有用。
    調(diào)用此函數(shù)前,應(yīng)確保 IO 設(shè)備已被打開。

4.4 打開設(shè)備

  • bool QIODevice::open(OpenMode mode) [virtual]
    打開設(shè)備,并將設(shè)備的打開方式設(shè)置為 mode 。如果設(shè)置成功,返回 true ;否則返回 false 。該函數(shù)應(yīng)該在任何 open() 函數(shù)的重實(shí)現(xiàn)中被調(diào)用,或任何其它用于打開的設(shè)備的函數(shù)中被調(diào)用。
  • bool QIODevice::isOpen() const
    如果設(shè)備已被打開,返回 true ,否則返回 false
    如果某設(shè)備可被讀取和(或)寫入,則該設(shè)備已被打開。默認(rèn)情況下,如果 openMode() 返回 NotOpen ,則該函數(shù)返回 false 。

4.5 關(guān)閉設(shè)備

公共函數(shù)

  • void QIODevice::close() [virtual]
    調(diào)用該函數(shù)后,首先會(huì)發(fā)射 aboutToClose() 信號(hào),然后關(guān)閉設(shè)備并將 OpenMode 設(shè)置為 NotOpen。錯(cuò)誤字符串也會(huì)被重置。

信號(hào)

  • void QIODevice::aboutToClose() [signal]
    當(dāng)設(shè)備即將關(guān)閉時(shí),便會(huì)發(fā)送此信號(hào)。如果在關(guān)閉設(shè)備之前需要執(zhí)行某些操作,可將其連接到此信號(hào)。比如,在一個(gè)獨(dú)立的緩沖區(qū)中,如果存在需要被寫入到設(shè)備中的數(shù)據(jù),便可利用該信號(hào)。以確保在設(shè)備關(guān)閉前,將這部分?jǐn)?shù)據(jù)被寫入到設(shè)備中。

4.6 讀取數(shù)據(jù)

讀取字符串

  • qint64 QIODevice::read(char *data, qint64 maxSize)
    從設(shè)備中最多讀取 maxSize 字節(jié)的數(shù)據(jù)到 data 中,并返回讀取到的字節(jié)數(shù)。如果發(fā)生錯(cuò)誤(比如嘗試從 WriteOnly 模式的設(shè)備中讀取數(shù)據(jù)),會(huì)返回 -1 。
    當(dāng)沒有更多的數(shù)據(jù)可供讀取時(shí),返回 0
    在數(shù)據(jù)流終止之后進(jìn)行讀取,同樣會(huì)報(bào)錯(cuò),即返回 -1 。比如讀取已關(guān)閉的套接字,或讀取已死掉的進(jìn)程。
  • QByteArray QIODevice::read(qint64 maxSize)
    這是一個(gè)重載函數(shù)。
    該函數(shù)會(huì)從設(shè)備讀取最多 maxSize 字節(jié)的數(shù)據(jù),并以 QByteArray 類型返回。
    該函數(shù)不能報(bào)告錯(cuò)誤,如果返回空 QByteArray 數(shù)組,可能意味著當(dāng)前沒有可供讀取的數(shù)據(jù),也可能意味著發(fā)生了錯(cuò)誤。

  • qint64 QIODevice::readData(char data, qint64maxSize*) [pure virtual protected]
    最多從設(shè)備中讀取 maxSize 字節(jié)的數(shù)據(jù)到 data 中,并返回讀取到的字節(jié)數(shù)。如果發(fā)生錯(cuò)誤,則返回 -1
    如果沒有讀取到任何字節(jié),并且以后也不會(huì)有更多可用字節(jié)時(shí),該函數(shù)會(huì)返回 -1 (比如套接字已關(guān)閉、管道已關(guān)閉、子進(jìn)程已結(jié)束)。
    該函數(shù)由 QIODevice 調(diào)用。創(chuàng)建 QIODevice 的子類時(shí),需要重實(shí)現(xiàn)該函數(shù)。
    重實(shí)現(xiàn)該函數(shù)時(shí),最重要的是在函數(shù)返回前讀取所有需要的數(shù)據(jù)。為了讓 QDataStream 能夠在類上運(yùn)行,這是必需的。QDataStream 會(huì)假定所有請(qǐng)求的信息都已被讀取,因此如果出現(xiàn)問題,也不會(huì)重新嘗試讀取數(shù)據(jù)。
    該函數(shù)可被調(diào)用(需要將參數(shù) maxSize 設(shè)置為 0),用于執(zhí)行 post-reading 操作。

  • qint64 QIODevice::readLine(char *data, qint64 maxSize)
    該函數(shù)會(huì)從設(shè)備中讀取一行 ASCII 字符(最多會(huì)讀取 maxSize -1 個(gè)字節(jié)),讀取到的字符被儲(chǔ)存在 data 中,返回值表示讀取到的字節(jié)數(shù)。如果某行無法被讀取,但也沒有發(fā)生錯(cuò)誤,該函數(shù)會(huì)返回 0 。如果發(fā)生錯(cuò)誤,該函數(shù)會(huì)返回可供讀取長(zhǎng)度,如果此時(shí)沒有可供讀取的數(shù)據(jù),則返回 -1 。
    Tips:該函數(shù)始終會(huì)在 data 的末尾添加終止符 \0 ,因此 maxSize 必須大于 1。
    滿足下列條件之一,便會(huì)停止讀取數(shù)據(jù):

    • 讀取到 \n 字符;
    • 已讀取到 maxSize - 1 個(gè)字節(jié);
    • 檢測(cè)到設(shè)備數(shù)據(jù)的結(jié)束。

    示例,以下代碼會(huì)從文件中讀取一行字符:

    QFile file("box.txt");
    if (file.open(QFile::ReadOnly)) {
        char buf[1024];
        qint64 lineLength = file.readLine(buf, sizeof(buf));
        if (lineLength != -1) {
            // the line is available in buf
        }
    }
    

    換行符 \n 同樣會(huì)包含在緩沖器中,如果在前 maxSize - 1 個(gè)被讀取到的字節(jié)中未包含換行符,則不會(huì)在緩沖器中插入換行符。在 Windows 中換行符會(huì)被替換為 \n 。
    該函數(shù)會(huì)調(diào)用 readLineData()readLineData() 通過重復(fù)調(diào)用 getChar() 實(shí)現(xiàn)。在自己的子類中可以重實(shí)現(xiàn) readLineData() 函數(shù),以為 readLine() 提供更高效的實(shí)現(xiàn)。

  • QByteArray QIODevice::readLine(qint64 maxSize = 0)
    此函數(shù)為重載函數(shù)。
    該函數(shù)會(huì)從設(shè)備讀取一行數(shù)據(jù),但是數(shù)據(jù)的長(zhǎng)度不超過 maxSize 個(gè)字符,返回值是 QByteArray 類型。
    該函數(shù)不能報(bào)告錯(cuò)誤,如果返回空 QByteArray 數(shù)組,可能意味著當(dāng)前沒有可供讀取的數(shù)據(jù),也可能意味著發(fā)生了錯(cuò)誤。

  • qint64 QIODevice::readLineData(char data, qint64maxSize*) [virtual protected]
    最多從設(shè)備中讀取 maxSize 字節(jié)的數(shù)據(jù)到 data 中,并返回讀取到的字節(jié)數(shù)。
    該函數(shù)由 readLine() 調(diào)用,并使用 getChar() 提供它的基本實(shí)現(xiàn)。帶有緩沖區(qū)的設(shè)備可以通過重實(shí)現(xiàn)該函數(shù)來提高 readLine() 的性能。
    readLine() 會(huì)向 data 追加 \0 字符,但是 readLineData() 不需要這樣做。
    如果需要重實(shí)現(xiàn)該函數(shù),一定要注意是否返回了正確的值:該函數(shù)應(yīng)返回在一行中讀取到的字節(jié)數(shù)(包含末尾處的換行符);如果此處沒有可供讀取的行,則返回 0 。如果發(fā)生錯(cuò)誤,當(dāng)且僅當(dāng)沒有字節(jié)被讀取時(shí),應(yīng)該返回 -1 。在 EOF(文件結(jié)束符)后進(jìn)行讀取被認(rèn)為錯(cuò)誤的。

  • QByteArray QIODevice::readAll()
    從設(shè)備中讀取所有剩余數(shù)據(jù),并以 QByteArray 類型返回。
    該函數(shù)不能報(bào)告錯(cuò)誤,如果返回空 QByteArray 數(shù)組,可能意味著當(dāng)前沒有可供讀取的數(shù)據(jù),也可能意味著發(fā)生了錯(cuò)誤。

讀取字符

  • bool QIODevice::getChar(char *c)
    從設(shè)備中讀取一個(gè)字符,并將其儲(chǔ)存在 c 中。如果 c 是 0,該字符會(huì)被丟棄。
    成功讀取,返回 true ;否則返回 false 。

  • void QIODevice::ungetChar(char c)
    將字符 c 放回到設(shè)備中。字符 c 會(huì)被放置在緩沖區(qū)的首位,其它內(nèi)容的位置依次后移一位,示例如下:

    port = QSerialPort('COM1')
    port.open(QIODevice.ReadWrite)
    
    print(port.readBufferSize())
    port.setReadBufferSize(2)
    print(port.readBufferSize())
    
    port.ungetChar(b'1')
    port.ungetChar(b'2')
    port.ungetChar(b'3')
    print(port.readAll())
    
    port.close()
    

    輸出:

    0
    2
    b'321'
    

    該函數(shù)常被用于撤銷 getChar() 操作。比如編寫回溯分析程序時(shí),便可使用該函數(shù)。
    如果之前并沒有從設(shè)備讀取 c ,則無法確定具體行為。
    Note: This function is not available while a transaction is in progress.

信號(hào)

  • void QIODevice::readyRead() [signal]
    在設(shè)備當(dāng)前的讀取通道中,每當(dāng)有可供讀取的新數(shù)據(jù)時(shí),該信號(hào)便會(huì)被發(fā)送一次。一旦有新數(shù)據(jù)可用,該信號(hào)便會(huì)被再次發(fā)送,比如當(dāng)新的網(wǎng)絡(luò)數(shù)據(jù)載荷已經(jīng)到達(dá)網(wǎng)絡(luò)套接字時(shí),便會(huì)發(fā)送該信號(hào)。另外當(dāng)新的數(shù)據(jù)塊被追加到設(shè)備時(shí),也會(huì)發(fā)送此信號(hào)。
    readyRead() 不會(huì)被遞歸發(fā)射,如果在連接到 readyRead() 的曹函數(shù)中重新進(jìn)入事件循環(huán),或在曹函數(shù)中調(diào)用 waitForReadyRead() ,那么 readyRead() 信號(hào)將不會(huì)重復(fù)發(fā)送( 雖然 waitForReadyRead() 仍然可能返回 true )。
    開發(fā)人員由 QIODevice 實(shí)現(xiàn)派生類時(shí),應(yīng)注意:每當(dāng)有新數(shù)據(jù)到達(dá)時(shí),總應(yīng)該發(fā)送 readyRead() 信號(hào)(不要僅因?yàn)樵诰彌_區(qū)中任然有數(shù)據(jù)被讀取,就發(fā)送該信號(hào))。在其它情況下情不要發(fā)送 readyRead() 信號(hào)。

其它函數(shù)

  • bool QIODevice::waitForReadyRead(int msecs) [virtual]
    該函數(shù)會(huì)阻塞調(diào)用,直到有可供讀取的新數(shù)據(jù)為止(同時(shí)會(huì)發(fā)送 readyRead() 信號(hào))。該函數(shù)會(huì)在 msecs 毫秒后發(fā)生超時(shí)。如果 msecs 被設(shè)置為 -1,則不會(huì)發(fā)生超時(shí)。
    如果存在可供讀取的新數(shù)據(jù),則返回 true ;如果發(fā)生錯(cuò)誤或操作超時(shí),則返回 false
    執(zhí)行該函數(shù)時(shí),無需事件循環(huán)。在編寫非 GUI 程序,以及在非 GUI 線程中執(zhí)行 I/O 操作時(shí),該函數(shù)會(huì)非常實(shí)用。
    如果在連接到 readRead() 信號(hào)的曹函數(shù)中調(diào)用 waitForReadyRead() ,那么 readyRead() 信號(hào)不會(huì)被重復(fù)發(fā)送。
    為自定義設(shè)備重實(shí)現(xiàn)該函數(shù)以提供非阻塞 API 時(shí),默認(rèn)的實(shí)現(xiàn)方式是什么也不做,并且返回 false 。
    <u>Warning:</u>從主(GUI)線程調(diào)用該函數(shù),可能會(huì)導(dǎo)致用戶界面凍結(jié)。

  • qint64 QIODevice::bytesAvailable() const [virtual]
    返回可供讀取的字節(jié)數(shù)。該函數(shù)通常配合順序設(shè)備使用,以便在讀取之前確定被分配到緩沖區(qū)中的字符數(shù)。
    重實(shí)現(xiàn)此函數(shù)的子類必須調(diào)用基本實(shí)現(xiàn),以包含 QIODevice 的緩沖區(qū)的尺寸。例如:

    qint64 CustomDevice::bytesAvailable() const
    {
        return buffer.size() + QIODevice::bytesAvailable();
    }
    
  • bool QIODevice::isReadable() const
    如果可以從設(shè)備讀取數(shù)據(jù)返回 true ,否則返回 false 。使用 byteAvailable() 可以確定可被讀取的字節(jié)數(shù)。
    該函數(shù)可以很方便的查詢?cè)O(shè)備的打開模式中是否包含 ReadOnly 標(biāo)識(shí)。

  • bool QIODevice::canReadLine() const [virtual]
    如果可以從設(shè)備讀取一行完整的數(shù)據(jù),會(huì)返回 true 。否則返回 false
    注意:無緩沖區(qū)的設(shè)備,由于無法確定可供讀取的內(nèi)容,因此總是返回 false 。
    該函數(shù)經(jīng)常同 readyRead() 信號(hào)一起被調(diào)用。
    重新實(shí)現(xiàn)此函數(shù)的子類必須調(diào)用基本實(shí)現(xiàn),以包含 QIODevice 的緩沖區(qū)的內(nèi)容。例如:

    bool CustomDevice::canReadLine() const
    {
        return buffer.contains('\n') || QIODevice::canReadLine();
    }
    

4.7 寫入數(shù)據(jù)

寫入字符串

  • qint64 QIODevice::write(const char *data, qint64 maxSize)
    data 中寫入最多 maxSize 字節(jié)的數(shù)據(jù)到設(shè)備中。
    返回實(shí)際被寫入的字節(jié)數(shù);如果發(fā)生錯(cuò)誤,則返回 -1。
  • qint64 QIODevice::write(const char *data)
    此函數(shù)是重載函數(shù)。
    將由 8-bit 字符組成的字符串(以 0 結(jié)尾),寫入到設(shè)備。
    返回實(shí)際被寫入的字節(jié)數(shù);如果發(fā)生錯(cuò)誤,則返回 -1。
    該函數(shù)相當(dāng)于:

    ...
    QIODevice::write(data, qstrlen(data));
    ...
    

    該函數(shù)在 Qt 4.5 被引入。

  • qint64 QIODevice::write(const QByteArray &byteArray)
    此函數(shù)是重載函數(shù)。
    byteArray 中的內(nèi)容寫入到設(shè)備。
    返回實(shí)際被寫入的字節(jié)數(shù);如果發(fā)生錯(cuò)誤,則返回 -1。

  • qint64 QIODevice::writeData(const char *data, qint64 maxSize) [pure virtual protected]
    data 中寫入最多 maxSize 字節(jié)的數(shù)據(jù)到設(shè)備中。
    返回被寫入的字節(jié)數(shù);如果發(fā)生錯(cuò)誤,則返回 -1。
    該函數(shù)由 QIODevice 調(diào)用。創(chuàng)建 QIODevice 的子類時(shí),需要重實(shí)現(xiàn)該函數(shù)。
    重實(shí)現(xiàn)該函數(shù)時(shí),最中要的是在函數(shù)返回前寫入所有可用的數(shù)據(jù)。為了讓 QDataStream 能夠在類上運(yùn)行,這是必需的。QDataStream 會(huì)假定所有的信息都已被寫入,因此如果出現(xiàn)問題,也不會(huì)嘗試重新寫入數(shù)據(jù)。

寫入字符

  • bool QIODevice::putChar(char c)
    將字符 c 寫入到設(shè)備。返回 true 表示寫入成功;否則返回 false 。

信號(hào)

  • void QIODevice::bytesWritten(qint64 bytes) [signal]
    每當(dāng)數(shù)據(jù)的有效載荷被寫入設(shè)備的當(dāng)前寫入通道時(shí),就會(huì)發(fā)出此信號(hào)。bytes 參數(shù)被設(shè)置為在有效載荷中被寫入的字節(jié)數(shù)。
    bytesWritten() 不會(huì)遞歸發(fā)射; 如果重新進(jìn)入事件循環(huán),或在連接到 bytesWritten() 信號(hào)的插槽內(nèi)調(diào)用 waitForBytesWritten(),信號(hào)將不會(huì)被重新發(fā)送(雖然 waitForBytesWritten() 仍然可以返回true)。

其它函數(shù)

  • bool QIODevice::waitForBytesWritten(int msecs) [virtual]
    對(duì)于擁有緩沖區(qū)的設(shè)備,該函數(shù)會(huì)一直等待,直到緩沖區(qū)寫入數(shù)據(jù)的有效載荷被寫入設(shè)備(同時(shí)會(huì)發(fā)送 bytesWritten() 信號(hào)),或是等待 msecs 毫秒后發(fā)生超時(shí)。如果 msecs 被設(shè)置為 -1,則不會(huì)發(fā)生超時(shí)。
    對(duì)于沒有緩沖區(qū)的設(shè)備,該函數(shù)會(huì)立即返回。
    如果數(shù)據(jù)的有效載荷已經(jīng)被寫入設(shè)備,則返回 true ;如果發(fā)生錯(cuò)誤或操作超時(shí),則返回 false 。
    執(zhí)行該函數(shù)時(shí),無需事件循環(huán)。在編寫非 GUI 程序,以及在非 GUI 線程中執(zhí)行 I/O 操作時(shí),該函數(shù)會(huì)非常實(shí)用。
    如果在連接到 bytesWritten() 信號(hào)的曹函數(shù)中調(diào)用 waitForBytesWritten() ,那么 bytesWritten() 信號(hào)不會(huì)被重復(fù)發(fā)送。
    為自定義設(shè)備重實(shí)現(xiàn)該函數(shù)以提供非阻塞 API 時(shí),默認(rèn)的實(shí)現(xiàn)方式是什么也不做,并且返回 false 。
    <u>Warning:</u>從主(GUI)線程調(diào)用該函數(shù),可能會(huì)導(dǎo)致用戶界面凍結(jié)。
  • qint64 QIODevice::bytesToWrite() const [virtual]
    對(duì)于擁有緩沖區(qū)的設(shè)備,該函數(shù)會(huì)返回等待寫入的字符數(shù)。
    對(duì)于沒有緩沖區(qū)的設(shè)備,該函數(shù)返回 0。
    重實(shí)現(xiàn)此函數(shù)的子類必須調(diào)用基本實(shí)現(xiàn),以包含 QIODevice 的緩沖區(qū)的尺寸。
  • bool QIODevice::isWritable() const
    如果可以向設(shè)備寫入數(shù)據(jù),則返回 true ;否則返回 false 。
    該函數(shù)可以很方便的查詢?cè)O(shè)備的打開模式中是否包含 WriteOnly 標(biāo)識(shí)。

4.8 查看數(shù)據(jù)

  • qint64 QIODevice::peek(char *data, qint64 maxSize)
    從設(shè)備中最多讀取 maxSize 字節(jié)的數(shù)據(jù)到 data 中,并返回讀取到的字節(jié)數(shù)。該函數(shù)不會(huì)有任何副作用,也就是所在 peek() 之后調(diào)用 read() ,將會(huì)獲得相同的數(shù)據(jù)。
    如果發(fā)生錯(cuò)誤(比如嘗試從 WriteOnly 模式的設(shè)備中查看數(shù)據(jù)),會(huì)返回 -1
    當(dāng)沒有更多的數(shù)據(jù)可供讀取時(shí),返回 0 。

    示例:

    {
        char buf[2];
        if (file->peek(buf, sizeof(buf)) == sizeof(buf))
            return (buf[0] == 'M' && buf[1] == 'Z');
        return false;
    }
    

    該函數(shù)在 Qt 4.1 被引入。

  • QByteArray QIODevice::peek(qint64 maxSize)
    這是一個(gè)重載函數(shù)。
    該函數(shù)會(huì)從設(shè)備查看最多 maxSize 字節(jié)的數(shù)據(jù),并以 QByteArray 類型返回。
    示例:

    bool isExeFile(QFile *file)
    {
        return file->peek(2) == "MZ";
    }
    

    該函數(shù)不能報(bào)告錯(cuò)誤,如果返回空 QByteArray 數(shù)組,可能意味著當(dāng)前沒有可供查看的數(shù)據(jù),也可能意味著發(fā)生了錯(cuò)誤。
    該函數(shù)在 Qt 4.1 被引入。

4.9 跳過數(shù)據(jù)

  • qint64 QIODevice::skip(qint64 maxSize)
    從設(shè)備中跳過最多 maxSize 字節(jié)。該函數(shù)會(huì)返回實(shí)際跳過的字節(jié)數(shù);發(fā)生錯(cuò)誤時(shí),返回 -1 。該函數(shù)不會(huì)等待,只會(huì)直接丟棄已經(jīng)存在的可供讀取的數(shù)據(jù)。如果設(shè)備以 text 模式被打開,則行結(jié)束符會(huì)被翻譯為 \n ,并在計(jì)數(shù)時(shí)被視作一個(gè)字節(jié)(這點(diǎn)同 read()peek() 的行為相同)。此函數(shù)適用與所有設(shè)備,包含不能使用 seek() 的順序設(shè)備。在 peek() 之后調(diào)用該函數(shù),可以很方便的跳過不想要的數(shù)據(jù)。對(duì)于隨機(jī)訪問設(shè)備,skip() 被用于從當(dāng)前位置向前查找。maxSize 不可使用負(fù)值。
    該函數(shù)在 Qt 5.11 被引入。

4.10 讀寫位置

  • bool QIODevice::seek(qint64 pos) [virtual]
    對(duì)于隨機(jī)訪問設(shè)備,該函數(shù)會(huì)將當(dāng)前位置設(shè)置為 pos 。如果設(shè)置成功,則返回 true ;如果發(fā)生錯(cuò)誤,則返回 false 。對(duì)于順序設(shè)備,默認(rèn)行為是產(chǎn)生警告并返回 false 。
    子類化 QIODevice 時(shí),必須在函數(shù)的開頭調(diào)用 QIODevice::seek() ,以確保 QIODevice 內(nèi)建緩沖區(qū)的完整性。
  • qint64 QIODevice::pos() const [virtual]
    對(duì)于隨機(jī)訪問設(shè)備,該函數(shù)會(huì)返回寫入或讀取數(shù)據(jù)的位置。對(duì)于順序設(shè)備或已關(guān)閉的設(shè)備而言,它們并沒有“當(dāng)前位置”的概念,因此會(huì)返回 0 。
    設(shè)備當(dāng)前的讀/寫位置由內(nèi)部的 QIODevice 維護(hù),因此該函數(shù)并非必須被重實(shí)現(xiàn)。在繼承 QIODevice 時(shí),需要使用 QIODevice::seek() 來通知 QIODevice 設(shè)備位置的變化。
  • bool QIODevice::reset() [virtual]
    查找隨機(jī)訪問設(shè)備輸入的起始位置。如果成功,返回 true ;否則返回 false (比如并未打開設(shè)備)
    注意,在 QFile 中使用 QTextStream 時(shí),由于 QTextStream 會(huì)緩存文件,所以在 QFile 上調(diào)用 reset() 將不會(huì)產(chǎn)生預(yù)期的結(jié)果,此時(shí)需要改用 QTextStream::seek() 函數(shù)。
  • bool QIODevice::atEnd() const [virtual]
    如果當(dāng)前讀寫位置處于設(shè)備的末端(即設(shè)備中沒有更多可供讀取的數(shù)據(jù)),將返回 true ;否則返回 false
    對(duì)于某些設(shè)備,即使仍有可被讀取的數(shù)據(jù),但是 atEnd() 也會(huì)返回 true 。這種特殊的情況僅適用于,間接響應(yīng) read() 調(diào)用來生成數(shù)據(jù)的設(shè)備(比如,在 Unix 和 MacOS 中的 /dev or /proc 文件,或是所有平臺(tái)上的 console input 和 stdin )。

4.11 信道

公共函數(shù)

  • int QIODevice::currentReadChannel() const
    返回當(dāng)前讀信道的索引值。
    該函數(shù)在 Qt 5.7 被引入。
  • int QIODevice::readChannelCount() const
    如果設(shè)備處于打開狀態(tài),則返回可用于讀取的信道的數(shù)量;否則返回 0。
    該函數(shù)在 Qt 5.7 被引入。
  • void QIODevice::setCurrentReadChannel(int channel)
    將 QIODevice 當(dāng)前的讀取通道設(shè)置為給定通道 channel 。當(dāng)前輸入通道會(huì)被 read(), readAll(), readLine(), getChar() 函數(shù)使用。還用于確定觸發(fā) QIODevice 發(fā)送 readyRead() 信號(hào)的通道。
    該函數(shù)在 Qt 5.7 被引入。
  • int QIODevice::currentWriteChannel() const
    返回當(dāng)前寫信道的索引值。
    該函數(shù)在 Qt 5.7 被引入。
  • int QIODevice::writeChannelCount() const
    如果設(shè)備處于打開狀態(tài),則返回可用于寫入的信道的數(shù)量;否則返回 0。
    該函數(shù)在 Qt 5.7 被引入。
  • void QIODevice::setCurrentWriteChannel(int channel)
    將 QIODevice 當(dāng)前的寫入通道設(shè)置為給定通道 channel 。當(dāng)前輸出通道會(huì)被 write(), putChar() 函數(shù)使用。還用于確定了觸發(fā) QIODevice 發(fā)送 bytesWritten() 信號(hào)的通道。
    該函數(shù)在 Qt 5.7 被引入。

信號(hào)

  • void QIODevice::channelReadyRead(int channel) [signal]
    當(dāng)有來自設(shè)備的可供讀取的新數(shù)據(jù)時(shí),便會(huì)發(fā)送此信號(hào)。 會(huì)將收到新數(shù)據(jù)的讀信道的索引值設(shè)置為 channel 的值。與 readyRead() 不同,無論當(dāng)前處于哪一個(gè)讀信道,該信號(hào)總會(huì)被發(fā)送。
    channelReadyRead() 可以被遞歸發(fā)送,即使處于同一的信道中。
    該函數(shù)在 Qt 5.7 被引入。
  • void QIODevice::readChannelFinished() [signal]
    當(dāng)設(shè)備中的輸入(讀?。┝鞅魂P(guān)閉時(shí),就會(huì)發(fā)送此信號(hào)。一旦檢測(cè)到流被關(guān)閉,便會(huì)發(fā)送此信號(hào),這意味著可能仍然存在可供讀取 read() 的數(shù)據(jù)。
    該函數(shù)在 Qt 4.4 被引入。
  • void QIODevice::channelBytesWritten(int channel, qint64 bytes) [signal]
    每當(dāng)數(shù)據(jù)有效載荷被寫入設(shè)備時(shí),便會(huì)發(fā)送該信號(hào)。有效載荷中被寫入的字節(jié)數(shù)會(huì)被設(shè)置為 bytes 的值;用于寫入數(shù)的信道的索引值會(huì)被設(shè)置為 channel 的值。與 bytesWritten() 不同,無論當(dāng)前處理哪一個(gè)寫信道,該信號(hào)總會(huì)被發(fā)送。
    channelBytesWritten() 可以被遞歸發(fā)送,即使處于同一信道中。
    該函數(shù)在 Qt 5.7 被引入。

4.12 設(shè)備類型查詢

  • bool QIODevice::isSequential() const [virtual]
    如果該設(shè)備是順序設(shè)備,則返回 true ;否則返回 false 。
    與隨機(jī)訪問設(shè)備相反,順序設(shè)備不具備如下概念:開始、結(jié)束、大小、當(dāng)前位置,也不支持查找位置(seek)。當(dāng)設(shè)備報(bào)告有可用數(shù)據(jù)時(shí),我們也只能從設(shè)備讀取數(shù)據(jù)。最常見的順序設(shè)備時(shí)網(wǎng)絡(luò)套接字。在 Unix 上,特殊文件也是順序設(shè)備(如 /dev/zero 和 fifo pipes )。
    另一方面,Regular files 支持隨機(jī)訪問。它們具備尺寸大小和當(dāng)前位置的概念,同時(shí)還支持在數(shù)據(jù)流中向后和向前查找位置(seek)。Regular files 是非順序設(shè)備。

4.13 設(shè)備大小查詢

  • qint64 QIODevice::size() const [virtual]
    對(duì)于已打開的隨機(jī)訪問設(shè)備,該函數(shù)會(huì)返回設(shè)備的 size。
    對(duì)于已打開的順序設(shè)備,該函數(shù)會(huì)返回 bytesAvailable()。
    如果設(shè)備已被關(guān)閉,返回值并不能反映出設(shè)備的實(shí)際 size。

4.14 事務(wù)處理

  • void QIODevice::startTransaction()
    在設(shè)備上啟動(dòng)新的讀取事務(wù)。
    在讀操作序列的內(nèi)部定義一個(gè)可還原點(diǎn)。對(duì)于順序設(shè)備,讀取的數(shù)據(jù)將在內(nèi)部被復(fù)制,以便在沒有完全讀取的情況下進(jìn)行恢復(fù)。對(duì)于隨機(jī)訪問設(shè)備,該函數(shù)會(huì)保存當(dāng)前位置。調(diào)用 commitTransaction() 或 rollbackTransaction() 可結(jié)束事務(wù)。
    注意:不支持嵌套事務(wù)。
    該函數(shù)在 Qt 5.7 被引入。
  • bool QIODevice::isTransactionStarted() const
    如果設(shè)備的進(jìn)程中存在已啟動(dòng)的事務(wù),則返回 true ,否則返回 false
    該函數(shù)在 Qt 5.7 被引入。
  • void QIODevice::rollbackTransaction()
    回滾讀取事務(wù)。
    將輸入流恢復(fù)到 startTransaction() 創(chuàng)建的還原點(diǎn)處。在提交事務(wù)之前,如果檢測(cè)到被讀取的數(shù)據(jù)并不完整,通常會(huì)使用該函數(shù)回滾事務(wù)。
    該函數(shù)在 Qt 5.7 被引入。
  • void QIODevice::commitTransaction()
    完成讀取事務(wù)。
    對(duì)于序列設(shè)備,在事務(wù)期間被記錄在內(nèi)部緩沖區(qū)中的所有數(shù)據(jù)都將被丟棄。
    該函數(shù)在 Qt 5.7 被引入。

4.15 錯(cuò)誤字符串

  • QString QIODevice::errorString() const
    以易于人類閱讀的方式,返回對(duì)最近發(fā)生的設(shè)備錯(cuò)誤的描述。
  • void QIODevice::setErrorString(const QString &str) [protected]
    str 設(shè)置為最近發(fā)生的設(shè)備錯(cuò)誤描述,str 包含的內(nèi)容要易于人類閱讀。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文會(huì)先介紹 Qt 自帶的串口模塊,然后引出在 PyQt5 中使用這些模塊的方法。為了演示類和函數(shù)的具體使用方法,...
    import_hello閱讀 13,686評(píng)論 1 4
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,652評(píng)論 18 399
  • 題目類型 a.C++與C差異(1-18) 1.C和C++中struct有什么區(qū)別? C沒有Protection行為...
    阿面a閱讀 7,887評(píng)論 0 10
  • 18/ 還是上一個(gè)七夕的事了。 Wendy老師來北京跟我們玩,走到車庫的時(shí)候代碼君讓我把Wendy老師的行李箱放進(jìn)...
    LittleJanel閱讀 304評(píng)論 0 0
  • 魂兮歸來 你倒下的時(shí)候 是否還穿著單衣 沖鋒的路上 你把槍彈看似風(fēng)霜 你倒下的時(shí)候 是否還望著故鄉(xiāng) 多難的厚土 燭...
    鴻波閱讀 207評(píng)論 0 0

友情鏈接更多精彩內(nèi)容