高效读取3MB文本文件,包括解析

时间:2017-07-16 22:08:57

标签: c++ boost file-handling

我需要在C ++中解析几个~3MB的文本文件。

文本文件如下所示(1024x786):

12,23   45,78   90,12   34,56   78,90   ...
12,23   45,78   90,12   34,56   78,90   ...
12,23   45,78   90,12   34,56   78,90   ...
12,23   45,78   90,12   34,56   78,90   ...
12,23   45,78   90,12   34,56   78,90   ...

表示"数字块"以Tab分隔,数字本身包含,.}小数点标记。

首先,我需要阅读该文件。目前我正在使用它:

#include <boost/tokenizer.hpp>

string line;
ifstream myfile(file);
if (myfile.is_open())
{
    char_separator<char> sep("\t");
    tokenizer<char_separator<char>> tokens(line, sep); 
}
myfile.close();

这对于让我成为&#34;数字块&#34;但我仍然需要将此char转换为浮点数,但将,作为小数点处理。由于文件大小,我认为tokenize这也不是一个好主意。此外,我需要将所有这些值添加到我之后可以按位置访问的数据结构(例如[x][y])。任何想法如何实现这一点?

2 个答案:

答案 0 :(得分:2)

您可以使用Boost.Spirit来解析文件的内容,作为最终结果,您可以从解析器中获取您喜欢的数据结构,例如std::vector<std::vector<float>>。 IMO,你的常见文件大小并不大。我相信将整个文件读入内存并执行解析器会更好。读取文件的有效解决方案如下所示read_file

qi::float_解析一个长度和大小受float类型限制的实数,并使用.(点)作为分隔符。您可以通过qi::real_policies<T>::parse_dot自定义分隔符。下面我使用的是spirit/example/qi/german_floating_point.cpp的代码段。

看一下这个演示:

#include <boost/spirit/include/qi.hpp>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

std::string read_file(std::string path)
{
    std::string str;
    std::ifstream file( path, std::ios::ate);
    if (!file) return str;
    auto size(file.tellg());
    str.resize(size);
    file.seekg(0, std::ios::beg);
    file.rdbuf()->sgetn(&str[0], size);
    return str;
}

using namespace boost::spirit;

//From Boost.Spirit example `qi/german_floating_point.cpp`
//Begin
template <typename T>
struct german_real_policies : qi::real_policies<T>
{
    template <typename Iterator>
    static bool parse_dot(Iterator& first, Iterator const& last)
    {
        if (first == last || *first != ',')
            return false;
        ++first;
        return true;
    }
};

qi::real_parser<float, german_real_policies<float> > const german_float;
//End

int main()
{
    std::string in(read_file("input"));
    std::vector<std::vector<float>> out;
    auto ret = qi::phrase_parse(in.begin(), in.end(),
                                +(+(german_float - qi::eol) >> qi::eol),
                                boost::spirit::ascii::blank_type{},
                                out);
    if(ret && in.begin() == in.end())
        std::cout << "Success" << std::endl;
}

答案 1 :(得分:0)

我会直接做什么(根本不需要boost::tokenizer):

std::setlocale(LC_NUMERIC, "de_DE"); // Use ',' as decimal point
std::vector<std::vector<double>> dblmat;
std::string line;
while(std::getline(myfile,line)) {
    dblmat.push_back(std::vector<double>());
    std::istringstream iss(line);
    double val;
    while(iss >> val) {
        dblmat.back().push_back(val);
    } 
} 
相关问题