如何将文件读入std::string
,即一次性读取整个文件?
文本或二进制模式应由调用方指定。该解决方案应该是符合标准的、可移植的和高效的。它不应该不必要地复制字符串的数据,并且应该避免在读取字符串时重新分配内存。
要做到这一点,一种方法是统计文件大小,将std::string
和fread()
调整为std::string
的const_cast<char*>()
'ed data()
。这要求std::string
的数据是连续的,这不是标准所要求的,但似乎所有已知的实现都是这样的。更糟糕的是,如果文件是以文本模式读取的,则std::string
的大小可能不等于文件的大小。
使用std::ifstream
的rdbuf()
可以构建一个完全正确的、符合标准的和可移植的解决方案到std::ostringstream
和std::string
中。然而,这可能会复制字符串数据和/或不必要的内存重新分配。
的隐藏Boost函数
void slurp(std::string& data, bool is_binary)
发布于 2008-09-22 17:22:30
一种方法是将流缓冲区刷新为单独的内存流,然后将其转换为std::string
std::string slurp(std::ifstream& in) {
std::ostringstream sstr;
sstr << in.rdbuf();
return sstr.str();
}
这是非常简洁的。然而,正如问题中所指出的,这执行了一个冗余拷贝,不幸的是,根本没有办法消除这个拷贝。
不幸的是,避免冗余副本的唯一真正的解决方案是在循环中手动读取。由于C++现在保证了连续字符串,因此可以编写以下代码(≥C++14):
auto read_file(std::string_view path) -> std::string {
constexpr auto read_size = std::size_t{4096};
auto stream = std::ifstream{path.data()};
stream.exceptions(std::ios_base::badbit);
auto out = std::string{};
auto buf = std::string(read_size, '\0');
while (stream.read(& buf[0], read_size)) {
out.append(buf, 0, stream.gcount());
}
out.append(buf, 0, stream.gcount());
return out;
}
发布于 2009-02-07 19:27:07
关于类似的问题,请参阅this answer。
为了您的方便,我重新发布了CTT的解决方案:
string readFile2(const string &fileName)
{
ifstream ifs(fileName.c_str(), ios::in | ios::binary | ios::ate);
ifstream::pos_type fileSize = ifs.tellg();
ifs.seekg(0, ios::beg);
vector<char> bytes(fileSize);
ifs.read(bytes.data(), fileSize);
return string(bytes.data(), fileSize);
}
当对《白鲸》(1.3M)的文本平均运行100次时,该解决方案的执行时间比这里提供的其他答案快了约20%。对于一个可移植的C++解决方案来说还不错,我想看看mmap文件的结果;)
发布于 2016-12-01 05:53:45
如果你有C++17 (std::filesystem),还有这种方法(它通过std::filesystem::file_size
而不是seekg
和tellg
来获取文件的大小):
#include <filesystem>
#include <fstream>
#include <string>
namespace fs = std::filesystem;
std::string readFile(fs::path path)
{
// Open the stream to 'lock' the file.
std::ifstream f(path, std::ios::in | std::ios::binary);
// Obtain the size of the file.
const auto sz = fs::file_size(path);
// Create a buffer.
std::string result(sz, '\0');
// Read the whole file into the buffer.
f.read(result.data(), sz);
return result;
}
注意:如果你的标准库还不完全支持<experimental/filesystem>
,你可能需要使用std::experimental::filesystem
和C++17。如果result.data()
不支持non-const std::basic_string data,你也可能需要用&result[0]
替换它。
https://stackoverflow.com/questions/116038
复制