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.pswp.cn/news/215838.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/215838.shtml
英文地址,請注明出處:http://en.pswp.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 概述 在立體匹配研究領域…