2011-06-23 104 views
6

我試圖從文件中讀取塊,並且出現問題。使用緩衝區來讀取未知大小的文件

char* inputBuffer = new char[blockSize] 
while (inputFile.read(inputBuffer, blockSize)) { 
    int i = inputFile.gcount(); 
//Do stuff 
} 

假設我們的塊大小爲1024 bytes,而該文件是24,3 KiB。讀完第23個街區後,會有0,3 KiB左側可供閱讀。我也想看看0,3 KiB,其實我以後用的是gcount(),所以我可以知道修改了多少緩衝區read(...)(萬一它少了)。
但是當它訪問第24個塊時,read(...)返回一個值使得程序不進入循環,顯然是因爲文件中其餘未讀字節的大小小於緩衝區大小。我該怎麼辦?

回答

3

我認爲你在另一個答案的評論中談論的康拉德魯道夫對於閱讀到eof的問題提出了一個很好的觀點。如果因爲其他錯誤而永遠無法到達eof,那麼您處於無限循環中。因此,請聽取他的建議,但修改它以解決您確定的問題。一種做法如下:

bool okay=true; 
while (okay) { 
    okay = inputFile.read(inputBuffer, blockSize); 
    int i = inputFile.gcount(); 
    if(i) { 
     //Do stuff 
    } 
} 

編輯:由於我的答案已被接受,我正在編輯它儘可能有用。事實證明,我的布爾沒關係是沒有必要的(參見ferosekhanj的回答)。最好直接測試inputFile的值,如果文件沒有打開,你也可以優雅地避免進入循環。所以我認爲這是解決這個問題的標準方法;

inputFile.open("test.txt", ios::binary); 
while (inputFile) { 
    inputFile.read(inputBuffer, blockSize); 
    int i = inputFile.gcount(); 
    if(i) { 
     //Do stuff 
    } 
} 

現在你最後一次//做的東西,我將小於塊大小,除了在該文件恰好是塊大小的倍數字節長的情況下。

Konrad Rudolf的回答here也不錯,它的優點是.gcount()只被調用一次,在循環之外,但缺點是它確實需要將數據處理放在一個單獨的函數中,以避免重複。

+0

您應該在「okay = inputFile.read(...)」之後包含一個if(好的),這樣可以確保程序不會使用無效數據。做到這一點,我將其標記爲可接受的答案。 – Erandros

+0

@Erandos,不會工作,因爲那麼你又回到了第1位 - 你將不會處理最後一個分區塊!相反,如果有(i),也許可以添加,這樣如果有數據,那麼你只會做東西。 –

+0

你說得對。我仍然認爲應該有一個「if(lessThanBufferSizeFlag)」。我不知道如何獲得那個標誌值。 – Erandros

1

但是,當它訪問第24個塊時,read(...)返回值使得程序不進入循環,顯然是因爲文件中其餘未讀字節的大小小於緩衝區尺寸。

這是因爲你的循環是錯誤的。你應該做的事:

while(!inputFile) { 
    std::streamsize numBytes = inputFile.readsome(inputBuffer, blockSize); 
//Do stuff 
} 

注意使用​​代替read

+0

該循環錯誤?這個100K的代表說反過來:http://stackoverflow.com/questions/6444876/c-reading-buffer-size/6444962#6444962雖然我會嘗試讀取。 – Erandros

+1

@Erandros:他還說,把閱讀內容放在while條件中是「更具可讀性」,這是我會爭辯的。在C/C++中做實際工作的條件語句可能是一個既定的習慣用法,但它不一定是一個好的或可讀的。 –

+0

我同意「更具可讀性」的問題。但是,如果我做一些讀取和失敗會發生什麼?我會繼續做有腐敗數據的東西。確保它永遠不會發生,同時也是好事。 – Erandros

3

@Konrad Rudolph提到的解決方案是檢查流對象本身,因爲它包括檢查eof和錯誤條件。 inputFile.read()返回inputFile本身的流,所以你可以這樣寫:

while(inputFile.read()) 

但是這不會總是有效。它失敗的情況是你的情況。一個合適的解決方案將寫入如下

char* inputBuffer = new char[blockSize] 
while (inputFile) 
{ 
    inputFile.read(inputBuffer, blockSize); 
    int count = inputFile.gcount(); 
    //Access the buffer until count bytes 
    //Do stuff 
} 

我認爲這是@Konrad魯道夫在他的帖子中意味着解決方案。從我以前的CPP經驗來看,我也會做類似上面的事情。

+0

這也適用。 – Erandros

+0

我同意,這是對我的解決方案的改進,所以+1做得好。 –

+0

我的解決方案對你的一個(非常輕微的)優勢是我只需要在循環之後檢查'gcount'一次(在循環內部它總是等於'blockSize')。我真的不喜歡進行不必要的操作,即使它們很便宜。也就是說,一旦處理緩衝區變得非常平凡(=多於一條語句),您的解決方案就會更好。 –