首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在C++中将整个文件读入std::string?

如何在C++中将整个文件读入std::string?
EN

Stack Overflow用户
提问于 2008-09-23 00:48:02
回答 20查看 100K关注 0票数 217

如何将文件读入std::string,即一次性读取整个文件?

文本或二进制模式应由调用方指定。该解决方案应该是符合标准的、可移植的和高效的。它不应该不必要地复制字符串的数据,并且应该避免在读取字符串时重新分配内存。

要做到这一点,一种方法是统计文件大小,将std::stringfread()调整为std::stringconst_cast<char*>()'ed data()。这要求std::string的数据是连续的,这不是标准所要求的,但似乎所有已知的实现都是这样的。更糟糕的是,如果文件是以文本模式读取的,则std::string的大小可能不等于文件的大小。

使用std::ifstreamrdbuf()可以构建一个完全正确的、符合标准的和可移植的解决方案到std::ostringstreamstd::string中。然而,这可能会复制字符串数据和/或不必要的内存重新分配。

  • 是否所有相关的标准库实现都足够智能,可以避免所有不必要的开销?
  • 是否有其他方法可以做到这一点?
  • 我是否错过了一些已提供所需functionality?

的隐藏Boost函数

代码语言:javascript
复制
void slurp(std::string& data, bool is_binary)
EN

回答 20

Stack Overflow用户

发布于 2008-09-23 01:22:30

一种方法是将流缓冲区刷新为单独的内存流,然后将其转换为std::string

代码语言:javascript
复制
std::string slurp(std::ifstream& in) {
    std::ostringstream sstr;
    sstr << in.rdbuf();
    return sstr.str();
}

这是非常简洁的。然而,正如问题中所指出的,这执行了一个冗余拷贝,不幸的是,根本没有办法消除这个拷贝。

不幸的是,避免冗余副本的唯一真正的解决方案是在循环中手动读取。由于C++现在保证了连续字符串,因此可以编写以下代码(≥C++14):

代码语言:javascript
复制
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;
}
票数 153
EN

Stack Overflow用户

发布于 2009-02-08 03:27:07

关于类似的问题,请参阅this answer

为了您的方便,我重新发布了CTT的解决方案:

代码语言:javascript
复制
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文件的结果;)

票数 55
EN

Stack Overflow用户

发布于 2016-12-01 13:53:45

如果你有C++17 (std::filesystem),还有这种方法(它通过std::filesystem::file_size而不是seekgtellg来获取文件的大小):

代码语言:javascript
复制
#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]替换它。

票数 32
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/116038

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档