Qt流緩衝的重新整理時間小解

2021-05-26 04:41:40 字數 3045 閱讀 2238

今天用

qtextstream

時候遇到了點點小問題,就是在寫入的時候,發現移動檔案指標不會覆蓋後面的資料。今天一天的時間基本上都放在了這個問題上面,下面具體說說。

例如下面的例子

qfile file(「c:/1.txt」);

qtextstream text(&file);

file.open(qfile::write);

text<<」1」<<」2」;

text.device().seek(0);

text<<」3」;

其它**略。下面執行了下面的**後,檔案顯示的內容為:

123,而不是我們希望的

32,這說明了

seek(0)

並沒有移動了檔案指標,這到底是怎麼回事呢?又如下面的**

qfile file(「c:/2.txt」);

qtextstream text(&file);

file.open(qfile::read);

qstring str;

text>>str;

qdebug()<

text.device().seek(0);

str.clear();

str=text.readall();

qdebug()<

執行後會發現並不是想象的那樣,輸出了第一行的字串後,輸出餘下的,而是輸出了餘下的後,再輸出全部的內容,這又是怎麼回事呢?

寫了一下午和晚上的**進行反覆的驗證,下面是得出的結論:

首先,對於

qtextstream

類來說,該類有個

buffer

,就是緩衝區,當我們向它繫結的

iodevice

寫入或者讀取資料時候,不會直接操作

device

,而是操作緩衝區,這樣做有個好處,避免頻繁的寫入硬碟,畢竟記憶體的速度比硬碟快多了。

qt就是這樣,

qtextstream

會將資料先存入緩衝區,在緩衝區操作,從而節省了系統資源。如第乙個例子,

text

繫結了1.txt

,第乙個寫入語句並沒有直接把內容寫入檔案中,而是寫入了記憶體中的緩衝區,當然緩衝區有大小,大於某大小後,或者主動進行重新整理時候,會將資料寫入檔案,但是我們的例子內容很少,所以都會讀入緩衝區,執行

seek

時候,file

的檔案指標的確是移動了,移動到了首行,然後再一次的寫入資料到了緩衝區,當主函式執行完畢時候,開啟檔案,內容是

123,下面我們把

seek

引數改為

2(用字為單位),再次執行主函式,會發現檔案的內容變成了空格

123,所以可以得出乙個結論,

seek

是有效的,但是因為實際寫入資料的時刻在

seek

之後,所以無法滿足我們原先的設想。

想實現原先的設想,我們可以直接操作

file

,所有的操作都是即時的,不受緩衝區重新整理的影響。另外,我們可以主動的去重新整理緩衝區,在所有

<<

操作符後加乙個

<;主動去重新整理緩衝區,這樣就可以直接把資料寫入物件中。

對於第二個例子,其實原理跟第乙個差不多。當要讀取某個檔案時候,當檔案的大小小於緩衝區大小限額時候,會將資料全部都讀取到緩衝區,並將

device

的pos

到最後,每次通過流來讀取檔案內容的時候,其實都在緩衝區進行操作,那麼我們設定指標其實都與緩衝區無關,因為資料的讀取在緩衝區而已。而在讀取了乙個字串(資料是一行一行的)之後,我們用了

seek(0)

函式,之後執行

readall()

發現資料是餘下的資料和原先的檔案中的所有資料,這是為什麼呢?

因為緩衝區有乙個大小的限額,假如檔案太大的話,會先讀入一部分到緩衝區,然後設定

device

的pos

為那最後部分,記憶體中的內容讀完後,會返回到原先設定的

pos,然後繼續讀取。明白了這個後,我們就可以很容易的明白為什麼會輸出那些奇怪的東西了。因為檔案實在是太小了,所以全部的讀入了記憶體緩衝區,然後先將第一行的字串輸出到

str,同時緩衝區也有乙個

pos,設定到了第一行的字串的末尾,末尾還有乙個回車。執行

readall()

函式時候,會將緩衝區的所有的內容全部輸出,也就是回車加上緩衝區的所有內容。那麼怎麼會出現此檔案的全部內容呢?答案是我們設定的

seek(0)

,因為當檔案太大的時候不能一次性的讀入記憶體緩衝區,剩下的資料該怎麼辦?所以會去查詢

device

的pos

,看是否到了結尾,正常情況下是到結尾的,有

2兩種情況: 1

.檔案能夠全部讀入記憶體緩衝區

這個情況很簡單,全部讀入後直接將

pos設定為結尾,這樣當

readall()

後發現已經到了檔案結尾了,結束函式,返回正常值。 2.

檔案不能全部讀入記憶體緩衝區

這個情況也很簡單,讀取一部分,並將

pos設定為截斷的部分,

readall()

後發現檔案沒到結尾,繼續讀入緩衝區,並輸出,直到到了檔案結尾。

我們的情況則是讀取過程中認為的執行了

seek(0)

,即改變了物件自動設定的

pos,這樣,當

pos檢測是否到檔案結尾時候,會發現沒有到!所以又一次的將檔案內容全部讀到緩衝區並且輸出,所以才會又輸出了一次全部內容,然後

pos發現到了檔案結尾,結束函式。

這樣,兩個問題都解決了。當然個人能力有限,無法完全明白

qiodevice

的原始碼,只能不斷的寫**進行測試。另外發現

qdatastream

輸入到device

一次後,就會自動重新整理,不用人工去重新整理,其實我這個問題是看

gui with qt4

的tcp

部分發現的。

今天又發現,假如使用qtextstream的pos()函式,會根據device重置流的位置和device的位置,然後清空流。而直接操作device的pos函式直接返回了當前的位置,不會進行任何操作。

linux流的緩衝

前面提到的所有i o函式都是針對檔案描述符的。當開啟乙個檔案時,即返回乙個檔案描述符,然後該檔案描述符就用於後讀的i o操作。而對於標準i o庫,它們的操作則是圍繞流 s t r e a m 進行的。為什麼要設計標準i o庫?直接使用api進行檔案訪問時,需要考慮許多細節問題 例如 read wri...

緩衝區 輸入輸出流控制 實時重新整理

為什麼需要緩衝區?1.將若干個字元作為乙個塊傳輸比逐個傳送這些字元耗費的時間少.2.如果輸入有錯誤,就可以使用您的鍵盤更正功能來修正錯誤.當最終按下回車鍵時,您就可以傳送正確的輸入.也有需要禁用緩衝區的情況 一些互動性的程式需要非緩衝區輸入,例如在遊戲中,你希望一按下鍵就執行某些命令.因此,緩衝和非...

帶緩衝的IO流和不帶緩衝的IO流

先來看看不帶快取的i o和標準 帶快取的 i o都有那些 不帶快取的i o read,write,open.標準 帶快取的 i o fgets,fread,fwrite.這裡使用兩個對應的函式進行比較 ssize t write int filedes,const void buff,size t ...