2016-12-19 54 views
3

最近我偶然發現一篇文章:How to read an entire file into memory in C++,其中描述了讀取文件的不同技術。每種方法都評論其效率或與未定義行爲相關的風險。 在列表下面的實例中,呈現:閱讀文件和未定義的行爲

// Bad code; undefined behaviour 
in.seekg(0, std::ios_base::end); 

這基本上在這個或類似的形式經常被用來實際讀取文件大小。 在後提出的推理,總之是,在C standard (N1570) §7.21.3它指出:

設置文件位置指示器到檔案結尾,與 FSEEK(文件,0,SEEK_END),對於二進制流 (由於可能結尾空字符)或任何具有 狀態相關編碼的流沒有明確的行爲,該編碼在初始 移位狀態中並未確實結束。

哪個footnote 268爲:

的文件不必開始也不在初始移位狀態

結束爲了確認上述用於C++ 11有一個附加的參考C++ standard draft (N3242) 27.9.1.1其中規定:

對讀寫控制序列的限制 basic_filebuf類的對象與用標準C庫FILE讀寫 的對象相同。

basic_filebuf根據cppreference是實施爲basic_ifstream(內部緩衝器)的一部分。表明ifstream實施應該也承擔着表示的行爲。

從我從描述和我設法挖掘的內容中瞭解到的情況來看,這個問題主要與面向廣泛的流有關,這些流可能不會以initial shift state結尾。

對我而言,由於文件大小計算的流行用法,這似乎不是典型情況。這個話題對我來說還不是很清楚。因此,以下問題

  • 究竟是initial state shift?我認爲它不能與數據集羣相關。更多的是多字節字符編碼,但這種方式不會僅限於非二進制流?
  • 實際上,我們處理wide-narrow-oriented流嗎?我知道:"A newly opened stream has no orientation."和方向是決定在第一個I/O調用流。但是在實踐中,假設有任何依賴於流類型,系統,語言環境或其他的默認值?
  • 如果還沒有回答或表示,那麼什麼時候會發生這種未定義的行爲的實際例子?從某種意義上說,可以複製它。

回答

3

"shift state" - 實際上僅限於多字節文本流(和EOL處理\r\n VS \n)和這個問題將僅限於文本流確實如此。

但這不是只有的問題。從您引用的文章中,我的重點是:

某些平臺將文件存儲爲固定大小的記錄。如果文件短於記錄大小,則塊的其餘部分將被填充。當你尋求「結束」時,爲了效率的緣故,它只是跳到最後一個塊的末尾......可能很長的在數據實際結束之後,經過一堆填充之後。

fseek(p_file, 0, SEEK_END)其次ftell(...)只只要EOF標誌沒有提出得到一個有效的答案。
請閱讀「解決方案(真正大文件)」部分的引用,因爲它提供了詳細信息,特別是:
第4步。「使用seekg()恢復流到起始位置。這也將清除EOF標誌。

問題的意見:

你有知識哪些平臺特別?

Google讓我着迷於面向記錄的文件系統的this list-主要是大型機,其中一些仍在使用。

另一個可能是「記錄文件」區域的區域是:「雲」。你永遠不知道什麼時候有人要(重新)體現Distributed Data Management Architecture,並遇到可由record-oriented files解決的問題。 對於我所知道的(幾乎沒有),NFS 可能已經在做:RFC談到「記錄鎖定」。在C/C++編寫「真正標準的,跨平臺兼容的軟件」時,我會關注標準並尊重這個問題。

+0

你是對的我也看到了。這會使獲取的大小不正確。結論仍然是:'你可以用二進制模式獲得ftell()的字符數......但是你不能用fseek(p_file,0,SEEK_END)來搜索文件的結尾。「此外,」一些平臺將文件存儲爲固定大小的記錄「聲明 - 您是否具有哪些平臺的知識?作者使用'gcount'提出的解決方案看起來有效。然而,我更感興趣的是在實踐中「尋求到最終獲取大小」的方法可能會失敗。 – Dusteh

+0

@Dusteh在答案中發佈了一些額外的信息。這就是說,我真的不知道如何在我可以使用的常用操作系統上重新制作「面向記錄的文件訪問」。 –