Qt SerialPort 與 PyQt5 (三)

本文用于介紹 QIODevice 類,該類是 QSerialPort 的父類。
系統(tǒng)環(huán)境:Win10 64位
轉(zhuǎn)載請注明出處:http://m.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)容的思維導圖:( 本節(jié)后面的內(nèi)容也遵循此結(jié)構(gòu) )


QIODevice.png

4.1 簡介

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

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

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

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

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

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

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

在主線程或 GUI 線程中調(diào)用以上函數(shù),可能會導致用戶界面凍結(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 的子類僅需要實現(xiàn)受保護的 readData() 和 writeData() 函數(shù)。QIODevice 使用這兩個函數(shù)來實現(xiàn)相關(guān)函數(shù)(如, getChar()、readLine() 和 write()),使操作更加便捷。QIODevice 還會為我們處理訪問控制,因此如果調(diào)用了 writeDate(),則可以安全地假定設(shè)備以寫模式打開。

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

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

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

4.2 創(chuàng)建對象

  • QIODevice::QIODevice()
    構(gòu)建一個 QIODevice 對象。
  • QIODevice::QIODevice(QObject *parent)
    使用給定的父對象構(gòu)建一個 QIODevice 對象。
  • QIODevice::~QIODevice() [virtual]
    該析構(gòu)函數(shù)是虛擬的,QIODevice 屬于抽象基類。該析構(gòu)函數(shù)不會調(diào)用 close(),但是其子類的析構(gòu)函數(shù)可能會調(diào)用。如果有疑慮,請在銷毀 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 以寫模式被打開,該模式意味著截斷
QIODevice::ReadWrite ReadOnly WriteOnly 以讀/寫模式打開
QIODevice::Append 0x0004 以追加模式打開設(shè)備,所有數(shù)據(jù)會被追加到文件的末尾。
QIODevice::Truncate 0x0008 如果可能的話,設(shè)備會在被打開之前截斷。 調(diào)用 open() 函數(shù)之前的內(nèi)容,都會丟失。
QIODevice::Text 0x0010 在讀取時,行終止符被轉(zhuǎn)換為 \n 。在寫入時,行終止符被轉(zhuǎn)換為平臺相關(guān)的本地編碼。比如 Win32 對應 \r\n
QIODevice::Unbuffered 0x0020 設(shè)備中的任何緩沖區(qū)都將被忽略。

因為子類表示的設(shè)備類型會隱含某些限制條件。所以某些標志 ( 如 UnbufferedTruncate ) 配合某些子類使用時,可能沒有實際意義。有些情況下,實現(xiàn)方式也會導致一些限制,另外底層平臺也會施加一些限制。例如,QTcpSocket 不支持 Unbuffered 模式;另外在 Windows 中由于本地 API 的限制,使得 QFile 不支持 Unbuffered模式。

flags QIODevice::OpenMode 是由 QFlags<PinoutSignal> 定義的類型。該類型可使用 OR 運算對 OpenMode 中的值進行組合。

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

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

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

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

4.4 打開設(shè)備

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

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

公共函數(shù)

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

信號

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

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

讀取字符串

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

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

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

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

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

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

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

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

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

讀取字符

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

  • void QIODevice::ungetChar(char c)
    將字符 c 放回到設(shè)備中。字符 c 會被放置在緩沖區(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è)備讀取 c ,則無法確定具體行為。
    Note: This function is not available while a transaction is in progress.

信號

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

其它函數(shù)

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

  • qint64 QIODevice::bytesAvailable() const [virtual]
    返回可供讀取的字節(jié)數(shù)。該函數(shù)通常配合順序設(shè)備使用,以便在讀取之前確定被分配到緩沖區(qū)中的字符數(shù)。
    重實現(xiàn)此函數(shù)的子類必須調(diào)用基本實現(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ù)可以很方便的查詢設(shè)備的打開模式中是否包含 ReadOnly 標識。

  • bool QIODevice::canReadLine() const [virtual]
    如果可以從設(shè)備讀取一行完整的數(shù)據(jù),會返回 true 。否則返回 false 。
    注意:無緩沖區(qū)的設(shè)備,由于無法確定可供讀取的內(nèi)容,因此總是返回 false 。
    該函數(shù)經(jīng)常同 readyRead() 信號一起被調(diào)用。
    重新實現(xiàn)此函數(shù)的子類必須調(diào)用基本實現(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è)備中。
    返回實際被寫入的字節(jié)數(shù);如果發(fā)生錯誤,則返回 -1。
  • qint64 QIODevice::write(const char *data)
    此函數(shù)是重載函數(shù)。
    將由 8-bit 字符組成的字符串(以 0 結(jié)尾),寫入到設(shè)備。
    返回實際被寫入的字節(jié)數(shù);如果發(fā)生錯誤,則返回 -1。
    該函數(shù)相當于:

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

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

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

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

寫入字符

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

信號

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

其它函數(shù)

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

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

  • qint64 QIODevice::peek(char *data, qint64 maxSize)
    從設(shè)備中最多讀取 maxSize 字節(jié)的數(shù)據(jù)到 data 中,并返回讀取到的字節(jié)數(shù)。該函數(shù)不會有任何副作用,也就是所在 peek() 之后調(diào)用 read() ,將會獲得相同的數(shù)據(jù)。
    如果發(fā)生錯誤(比如嘗試從 WriteOnly 模式的設(shè)備中查看數(shù)據(jù)),會返回 -1 。
    當沒有更多的數(shù)據(jù)可供讀取時,返回 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)
    這是一個重載函數(shù)。
    該函數(shù)會從設(shè)備查看最多 maxSize 字節(jié)的數(shù)據(jù),并以 QByteArray 類型返回。
    示例:

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

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

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

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

4.10 讀寫位置

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

4.11 信道

公共函數(shù)

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

信號

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

4.12 設(shè)備類型查詢

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

4.13 設(shè)備大小查詢

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

4.14 事務處理

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

4.15 錯誤字符串

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

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

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

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