2012-01-12 58 views
2

我有以下簡單的代碼,讀取一個文本文件的內容轉換成字符數組:ifstream的讀取文本文件中錯誤的字符

const char* name = "test.txt"; 
std::cout << "Loading file " << name << std::endl; 
std::ifstream file; 
file.open(name); 
file.seekg (0, std::ios::end); 
int length = file.tellg(); 
std::cout << "Size: " << length << " bytes" << std::endl; 
file.seekg (0, std::ios::beg); 
char* buffer = new char[length]; 
file.read(buffer,length); 
file.close(); 
std::cout.write(buffer,length); 

然而,似乎ifstream的讀取錯誤的號碼從文件字符的:每行1個附加字符。我通過網絡搜索,它看起來像win7文本文件除了在每行的末尾換行符(\ n)有回車符號(\ r)。但是,流不知何故不會看到這些\ r,但仍使用文件中原始數量的符號,從文件末尾讀取其他字節。有沒有可能以某種方式解決這個問題?

如果有幫助:我使用MinGW編譯器和Windows 7 64位。

+0

也許你可以使用'readsome'函數來看看你實際讀了多少? – Nim 2012-01-12 11:00:25

回答

6

您可能希望以二進制方式打開文件:

file.open(name, ios_base::in | ios_base::binary); 

否則會發生什麼是標準庫會把每一個Windows換行符(CR + LF)到一個單一的\n你。

這意味着您可以從文件中讀取的字符數與文件大小不同。當您撥打read()時,它會盡可能多地讀取字符。如果無法讀取您請求的字符數,則會設置流的failbit

+0

是的,它的工作原理。謝謝! – 2012-01-12 11:07:50

+0

在Windows上。不一定在其他系統上。 – 2012-01-12 11:50:19

+0

你節省了我的一天,謝謝。 – withparadox2 2017-09-10 09:52:44

0

閱讀有關binary閱讀的文件(谷歌或查看here)。

0

你從一些非常錯誤(但普遍)的觀點開始。 file.tellg()不返回int;它會返回一個實現 定義的類型爲streampos的對象,該對象必須是類類型,並且可能不會被轉換爲整數類型。如果它是 可轉換爲一個整數類型(我不知道它的實現 不是,即使它不是必需的),但不能保證產生的整數代表什麼不只是一個魔術其中的 將允許reseeking到相同的位置。

實際上,這在現代機器上可能不是一個大問題:Unix和Windows都從文件的開頭返回字節偏移量。 在Unix的情況下,這可以正常工作,因爲 內部表示映射到外部表示是一對一的。在Windows的 的情況下,存在行結尾的重新映射:在文本文件中,行 結尾是兩個字節的0x0D,0x0A的序列,其在讀取時變爲 單個字符'\n'。並且streampos(轉換爲整數類型) 以字節爲單位給出了您必須在文件中查找的位置,而不是 您需要讀取以獲取該位置的字符數。對於你似乎在做的事情 ,這不是一個問題;分配的 緩衝區可能會比必要的大一點,但它永遠不會太小 。

請注意,這可能不適用於大型機。歷史上,至少在 ,大型機使用面向塊的文件,並且一個 streampos的積分值可以很容易被分成幾個字段, 塊號的一定數量的位,其他位的字節 偏移該塊。根據這些字符的排列方式, 分配的緩衝區可能很容易產生太大的幾個數量級,或者如果偏移量置於高位,則太小。

得到你需要緩衝的確切大小的唯一可靠的方法是 系統相關,在某些系統(包括Windows),也可以通過讀取所有的字符計數他們是 沒有其他辦法時除外。

(原因streampos要求是類類型是因爲, 歷史上,許多老年人多字節編碼過的編碼狀態;你 不能正確地不知道什麼字符 它之前解碼性格讓streampos是。 。含有兩種不同 信息要求:尋求在文件中的位置,以及有關 這種狀態下,我不認爲有任何依賴於狀態的多字節編碼 廣泛使用的今天,不過)