ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c – 将文件读入std :: string的最有效方法是什么?

2019-10-09 05:20:10  阅读:118  来源: 互联网

标签:c string file-io


我目前这样做,最后转换为std :: string需要98%的执行时间.一定会有更好的办法!

std::string
file2string(std::string filename)
{
    std::ifstream file(filename.c_str());
    if(!file.is_open()){
        // If they passed a bad file name, or one we have no read access to,
        // we pass back an empty string.
        return "";
    }
    // find out how much data there is
    file.seekg(0,std::ios::end);
    std::streampos length = file.tellg();
    file.seekg(0,std::ios::beg);
    // Get a vector that size and
    std::vector<char> buf(length);
    // Fill the buffer with the size
    file.read(&buf[0],length);
    file.close();
    // return buffer as string
    std::string s(buf.begin(),buf.end());
    return s;
}

解决方法:

作为C迭代器抽象和算法的忠实粉丝,我希望以下是将文件(或任何其他输入流)读入std :: string(然后打印内容)的禁食方式:

#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>

int main()
{
    std::string s(std::istreambuf_iterator<char>(std::ifstream("file")
                                                 >> std::skipws),
                  std::istreambuf_iterator<char>());
    std::cout << "file='" << s << "'\n";
}

对于我自己实现的IOStream来说,这当然很快,但实际上要快速实现它需要很多技巧.首先,它需要优化算法来处理分段序列:流可以被视为输入缓冲器序列.我不知道任何STL实现始终如一地进行此优化. std :: skipws的奇怪用法只是为了引用刚刚创建的流:std :: istreambuf_iterator< char>期望临时文件流不会绑定的引用.

由于这可能不是最快的方法,我倾向于将std :: getline()与特定的“换行符”字符一起使用,即不在文件中:

std::string s;
// optionally reserve space although I wouldn't be too fuzzed about the
// reallocations because the reads probably dominate the performances
std::getline(std::ifstream("file") >> std::skipws, s, 0);

这假定该文件不包含空字符.任何其他角色都可以.不幸的是,std :: getline()将char_type作为分隔参数,而不是成员std :: istream :: getline()用于分隔符的int_type:在这种情况下,您可以对字符使用eof()从不发生(char_type,int_type和eof()引用char_traits< char>)的相应成员.反过来,成员版本无法使用,因为您需要提前知道文件中有多少个字符.

顺便说一句,我看到一些尝试使用seek来确定文件的大小.这一定不会太好用.问题是在std :: ifstream中完成的代码转换(实际上在std :: filebuf中)可以创建与文件中的字节不同的字符数.不可否认,使用默认的C语言环境时并非如此,并且可以检测到这不会进行任何转换.否则,流的最佳选择是遍历文件并确定正在生成的字符数.我实际上认为这是代码转换可能需要做的事情,尽管我认为它实际上并没有完成.但是,没有一个示例使用例如明确设置C语言环境.的std ::区域::全球(标准::区域( “C”));.即使这样,也需要以std :: ios_base :: binary模式打开文件,因为否则在读取时行尾序列可能被单个字符替换.不可否认,这只会使结果更短,而不会更长.

使用std :: streambuf *提取的其他方法(即涉及rdbuf()的方法)都要求在某些时候复制结果内容.鉴于该文件实际上可能非常大,这可能不是一种选择.但是,如果没有副本,这很可能是最快的方法.为了避免复制,可以创建一个简单的自定义流缓冲区,它将std :: string的引用作为构造函数参数并直接附加到此std :: string:

#include <fstream>
#include <iostream>
#include <string>

class custombuf:
    public std::streambuf
{
public:
    custombuf(std::string& target): target_(target) {
        this->setp(this->buffer_, this->buffer_ + bufsize - 1);
    }

private:
    std::string& target_;
    enum { bufsize = 8192 };
    char buffer_[bufsize];
    int overflow(int c) {
        if (!traits_type::eq_int_type(c, traits_type::eof()))
        {
            *this->pptr() = traits_type::to_char_type(c);
            this->pbump(1);
        }
        this->target_.append(this->pbase(), this->pptr() - this->pbase());
        this->setp(this->buffer_, this->buffer_ + bufsize - 1);
        return traits_type::not_eof(c);
    }
    int sync() { this->overflow(traits_type::eof()); return 0; }
};

int main()
{
    std::string s;
    custombuf   sbuf(s);
    if (std::ostream(&sbuf)
        << std::ifstream("readfile.cpp").rdbuf()
        << std::flush) {
        std::cout << "file='" << s << "'\n";
    }
    else {
        std::cout << "failed to read file\n";
    }
}

至少使用适当选择的缓冲区,我希望版本相当快.哪个版本最快将取决于系统,正在使用的标准C库,以及可能还有许多其他因素,即您想要衡量性能.

标签:c,string,file-io
来源: https://codeday.me/bug/20191009/1876919.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有