在 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);
}