今天用
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 ...