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

作者: dirkc (3781615)   2015-05-23 02:46:26
直接回一篇好了
答案如同其他版友已經提供的,我只想補充嚴格說來 '\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):
作者: out99 ( )   2015-05-23 09:34:00
_stat在Windows下正常運作,而且速度也比較快受教了,感謝!我剛剛用stat在Windows下測試一樣能運作我是用VS2013
作者: Killercat (殺人貓™)   2015-05-23 11:54:00
我倒是沒有碰過ASCII檔案裡面夾\0的例子就是(抓頭如果夾\0 我想fstream的<<應該會死光才對

Links booklink

Contact Us: admin [ a t ] ucptt.com