在 C++ 中將檔案讀入到字串
本文將講解幾種在 C++ 中把檔案內容讀取到 std::string
的方法。
使用 istreambuf_iterator
在 C++ 中將檔案讀入到字串
istreambuf_iterator
是一個輸入迭代器,從 std::basic_streambuf
物件中讀取連續的字元。因此,我們可以利用 istreambuf_iterator
與 ifstream
流一起使用,並將檔案的全部內容讀取到 std::string
中。
首先,我們開啟一個給定的檔案路徑作為 ifstream
物件。然後,我們可以將 istreambuf_iterator<char>(input_file)
傳遞給 string
建構函式,並在第一時間得到我們需要的物件。注意,我們是直接傳遞 string
建構函式語句,從函式中返回。程式的輸出應該是由 filename
變數指定的檔案內容。
#include <fstream>
#include <iostream>
#include <sstream>
using std::cerr;
using std::cout;
using std::endl;
using std::ifstream;
using std::ostringstream;
using std::string;
string readFileIntoString(const string& path) {
ifstream input_file(path);
if (!input_file.is_open()) {
cerr << "Could not open the file - '" << path << "'" << endl;
exit(EXIT_FAILURE);
}
return string((std::istreambuf_iterator<char>(input_file)),
std::istreambuf_iterator<char>());
}
int main() {
string filename("input.txt");
string file_contents;
file_contents = readFileIntoString(filename);
cout << file_contents << endl;
exit(EXIT_SUCCESS);
}
在 C++ 中使用 rdbuf
將檔案讀入字串
rdbuf
函式是一個內建的方法,用來返回檔案的流緩衝區的指標,這對於使用 <<
運算子將檔案的全部內容插入到需要的物件中是很有用的。
在下面的例子中,我們構造了一個 ostringstream
物件,在這個物件中插入 rdbuf
函式的返回值。函式本身返回的是 string
物件,所以使用 str
方法來獲取最終的返回值。
#include <fstream>
#include <iostream>
#include <sstream>
using std::cerr;
using std::cout;
using std::endl;
using std::ifstream;
using std::ostringstream;
using std::string;
string readFileIntoString2(const string& path) {
auto ss = ostringstream{};
ifstream input_file(path);
if (!input_file.is_open()) {
cerr << "Could not open the file - '" << path << "'" << endl;
exit(EXIT_FAILURE);
}
ss << input_file.rdbuf();
return ss.str();
}
int main() {
string filename("input.txt");
string file_contents;
file_contents = readFileIntoString2(filename);
cout << file_contents << endl;
exit(EXIT_SUCCESS);
}
使用 fread
將檔案讀入字串
另一種讀取檔案的方法是 C 標準庫函式 fread
。這種方法需要相對較舊的函式,在現代 C++ 程式碼庫中並不常見,但與以前的方法相比,它在速度方面有優勢。
fread
需要四個引數。
- 一個指向儲存讀取資料的緩衝區的指標。
- 資料項的大小。
- 資料項的數量。
- 讀取的檔案指標。
由於我們要讀的是整個檔案,所以需要檢索檔案大小,並通過 Unix 系統呼叫 stat
實現。檢索到檔案大小後,我們將其值作為資料元素的大小傳遞給 fread
函式,並將資料項的數目指定為 1
。
需要注意的是,開啟的檔案需要用 fclose
函式呼叫來關閉,它的唯一引數是檔案指標。
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
using std::cerr;
using std::cout;
using std::endl;
using std::string;
string readFileIntoString3(const string& path) {
struct stat sb {};
string res;
FILE* input_file = fopen(path.c_str(), "r");
if (input_file == nullptr) {
perror("fopen");
}
stat(path.c_str(), &sb);
res.resize(sb.st_size);
fread(const_cast<char*>(res.data()), sb.st_size, 1, input_file);
fclose(input_file);
return res;
}
int main() {
string filename("input.txt");
string file_contents;
file_contents = readFileIntoString3(filename);
cout << file_contents << endl;
exit(EXIT_SUCCESS);
}
使用 read
將檔案讀成字串
read
方法是符合 POSIX 標準的函式呼叫,在各種作業系統上都可以使用,如果程式設計師懂得有效地運用它,那麼它可以成為最靈活的一種方法。fread
本身會在下面呼叫 read
,但這並不能保證在所有情況下都有更快的操作,因為多種因素對這種系統呼叫的有效使用起著影響。
與 fread
的主要區別在於,read
需要一個檔案描述符引數來指向從哪裡讀取資料的檔案。檔案描述符是與程式在執行過程中可能具有的開啟的檔案流相關聯的特殊整數。它可以使用 open
函式呼叫獲得,並以 int
型別儲存。read
函式的另外兩個引數是指向將儲存資料的緩衝區的指標和需要讀取的位元組數,後者用 fstat
函式呼叫檢索。注意,我們使用 string.data
作為緩衝區來儲存讀取的檔案內容。
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
using std::cerr;
using std::cout;
using std::endl;
using std::string;
string readFileIntoString4(const string& path) {
struct stat sb {};
string res;
int fd = open(path.c_str(), O_RDONLY);
if (fd < 0) {
perror("open\n");
}
fstat(fd, &sb);
res.resize(sb.st_size);
read(fd, (char*)(res.data()), sb.st_size);
close(fd);
return res;
}
int main() {
string filename("input.txt");
string file_contents;
file_contents = readFileIntoString4(filename);
cout << file_contents << endl;
exit(EXIT_SUCCESS);
}