将以文本模式打开的整个文件读入字符串变量的最佳方法

时间:2010-12-12 16:09:59

标签: c++ file

这些是无法更改的内容:

  • 语言是C ++
  • 但是,该文件是使用旧的fopen()
  • 打开的
  • 文件未以二进制模式打开

这就是我要做的事情:

  • 编写一个将整个文件加载到std::string的函数。行应仅由\n分隔,而不是其他变体。

这就是我所做的:

string ReadWhole()
{
    Seek(0);
    char *data = new char[GetSize()];

    if (1 != fread(data, GetSize(), 1, mFile))
        FATAL(Text::Format("Read error: {0}", strerror(errno)));

    string ret(data, GetSize());
    delete[] data;
    return ret;
}

作为参考,这是GetSize,但它只返回文件的大小(缓存):

int GetSize()
{
    if (mFileSize)
        return mFileSize;

    const int current_position = ftell(mFile);
    fseek(mFile, 0, SEEK_END);
    mFileSize = ftell(mFile);
    fseek(mFile, current_position, SEEK_SET);

    return mFileSize;
}

这是问题

fread()失败,因为该文件有\r\n行结尾,并且它们只计为1个字符而不是2个字符,所以它尝试读取的内容超过文件中的字符。

我可以用fgets修复它,但我想知道是否有更好的方法。感谢。

4 个答案:

答案 0 :(得分:3)

fread返回后无法读取请求的字节数,您应该只检查ferror(mFile)。如果它是0(假),那么fread只是停在文件的末尾,你不应该把它作为一个错误。你应该切换两个参数,这样你就可以获得实际读取的字节数:

size_t number_of_bytes_read = fread(data, 1, GetSize(), mFile);

答案 1 :(得分:2)

执行此操作有一种微不足道的惯用方法。

#include <string>
#include <fstream>
#include <sstream>
std::string load_file ( const std::string& path ) 
{
    std::ostringstream contents;
    std::ifstream file(path);
    if ( !file.is_open() ) {
        // process error.
    }
    contents << file.rdbuf();
    return (contents.str());
}

注意:此函数使用寻求获取输入文件的大小(以字节为单位)。这有(少数)重新分配的缺点,以增加缓冲区,因为有更多的输入可用。它具有与其他std::istream实现一起工作的优势,这些实现可能无法提前提供内容的大小(即从套接字读取)。

修改:因为您的要求声明使用已经打开且无法更改的FILE*,您可以实施使用现有{{1}的std::streambuf实施允许重复使用高级FILE*std::istream操作。

可以使用示例实现right here, on StackOverflow

P.S。:如果您从未使用过非标准库流缓冲区实现,请按照我指出的实现快速概述如何编写函数。

std::ostream

答案 2 :(得分:0)

你可以分配一个固定大小的缓冲区,并且最多可以从文件中重复fread并将其附加到string::apeend(char*, size_type)的字符串中。

答案 3 :(得分:0)

只需使用fgetc()一次读取一个字符。您可以使用特殊情况将'\ r \ n'结尾转换为普通'\ n'。

std::string ReadWhole() {
    std::string ret;
    char prev = 0, c;
    while ((c = fgetc(mFile)) != EOF) {
        if (prev == '\r' && c == '\n') {
            ret.erase(ret.rend()); // erase the previous \r
        }
        ret += c;
        prev = c;
    }
    return ret;
}