Re: [問題] C++ 將檔案讀入 std::string

看板C_and_CPP作者 (3781615)時間10年前 (2015/05/23 02:46), 編輯推噓2(204)
留言6則, 2人參與, 最新討論串3/3 (看更多)
直接回一篇好了 答案如同其他版友已經提供的,我只想補充嚴格說來 '\0' 也是 ASCII 字元 如果你的輸入檔案裡面原先有 '\0' 字元,你的方法「有可能」會失敗 舉例來說,如果輸入檔案 test.in 內容以十六進位顯示如下 68 65 6c 6c 6f 00 20 77 6f 72 6c 64 21 0a 以可顯示的 ASCII 字元就會如下: hello. world!. 第一個 . 是 '\0' 第二個 . 是 '\n' 顯示不出來我們暫時用 . 來代表 如果以你的讀檔方式,在 linux/g++ 4.8.2 上面只會讀到 hello, getline() 碰到檔案中的 '\0' 就停止了 上面提到的「有可能」是因為 text mode 開檔會做一些 ASCII 特殊字元的轉換, 至於會做哪方面的轉換,則要看作業系統和/或函數庫的實作而定, 或許以上的例子在 Windows/VC++ 上面跑會跳過 '\0' 繼續讀到檔案結尾也不一定 (我沒有在 Windows 上實驗過) 我自己不會太建議用 getline() 來讀整個檔案,畢竟它是一個字元一個字元去做 判斷,直覺上讀取速度會很慢,尤其檔案大的時候 版友提的 iterator 或 streambuf 的作法很簡潔漂亮,不過檔案大速度可能也會慢 (抱歉單純就事論事) 通常判斷完檔案的大小之後,一次將檔案讀取進來,速度通常會比較快 舉例來說,稍微小修一下你的程式: #include <iostream> #include <fstream> #include <string> using namespace std; int main(int argc, char **argv) { string str; ifstream fin(argv[1]); if(!fin) return 1; fin.seekg(0, ios::end); str.resize(fin.tellg()); fin.seekg(0, ios::beg); fin.read(&str[0], str.size()); fin.close(); cout << str; } 以上我在 linux 實驗可以,但據說有人用 text mode 使用 seekg(0, ios::end) 會失 敗,所以另一種作法也提供給你參考,就是使用 POSIX 的 stat() 函數和 struct stat 來取得檔案大小,再一次將檔案讀取進來 (在 Windows 下是 _stat() 函數和 struct _stat) 舉例: #include <sys/types.h> #include <sys/stat.h> #include <fstream> #include <string> #include <iostream> using namespace std; int main(int argc, char **argv) { ifstream fin(argv[1]); if(!fin) return 1; struct _stat s; string str; if(_stat(argv[1], &s)) return 1; str.resize(s.st_size); fin.read(&str[0], str.size()); fin.close(); cout << str; } 記得最前面的兩個 #include 上例我在 linux 實驗可以運作,於是直接把程式碼 stat 前面加底線變成 Windows 版本 沒意外的話應該可以用 以上提供給你參考 ※ 引述《out99 ( )》之銘言: : 開發平台(Platform): (Ex: VC++, GCC, Linux, ...) : VC++ : 額外使用到的函數庫(Library Used): (Ex: OpenGL, ...) : 問題(Question): : 我想要一次將整個檔案讀進 std::string : 而不是用 while 一行一行讀取再 append string : 我直接使用 std::getline() 第三個參數 delim 丟入 '\0' 處理 : 測試過幾個檔案「看起來」沒有問題 : 我想問的是會不會有特殊情形導致這個方式讀出來的內容是錯誤的? : 直接假設「檔案的第一個 '\0' 字元就是整個檔案的結尾」是正確的嗎? : 謝謝 : 餵入的資料(Input): : 內容為 ASCII 字元,不包含其它特殊字元的文字檔。 : 預期的正確結果(Expected Output): : 錯誤結果(Wrong Output): : 程式碼(Code):(請善用置底文網頁, 記得排版) : #include <iostream> : #include <string> : #include <fstream> : using namespace std; : int main(int argc, char** argv) : { : string str; : ifstream fin(argv[1], ios::in); : if (fin.fail()) : return 1; : getline(fin, str, '\0'); : fin.close(); : cout << str; : return 0; : } : 補充說明(Supplement): -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 111.249.172.143 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1432320388.A.68E.html

05/23 09:34, , 1F
_stat在Windows下正常運作,而且速度也比較快
05/23 09:34, 1F

05/23 09:34, , 2F
受教了,感謝!
05/23 09:34, 2F

05/23 09:47, , 3F
我剛剛用stat在Windows下測試一樣能運作
05/23 09:47, 3F

05/23 09:48, , 4F
我是用VS2013
05/23 09:48, 4F

05/23 11:54, , 5F
我倒是沒有碰過ASCII檔案裡面夾\0的例子就是(抓頭
05/23 11:54, 5F

05/23 11:55, , 6F
如果夾\0 我想fstream的<<應該會死光才對
05/23 11:55, 6F
文章代碼(AID): #1LNtc4QE (C_and_CPP)
文章代碼(AID): #1LNtc4QE (C_and_CPP)