2013-05-10 29 views
1

我需要读取浮动文件并将其推送到我的矢量中。我可以通过使用临时浮点数来让他工作,但是我现在没有尝试。将文件流式传输到矢量<float> with copy + back_inserter

出于某种原因,以下内容不起作用。

std::ifstream fileHandle(filename); 
std::vector<float> vect; 
std::string id; 
while (!fileHandle.eof()){ 
    fileHandle >> id; 
    std::copy(std::istream_iterator<float>(fileHandle), 
       std::istream_iterator<float>(), 
       std::back_inserter(vect)); 
    std::copy(std::istream_iterator<float>(fileHandle), 
       std::istream_iterator<float>(), 
       std::back_inserter(vect)); 
    std::copy(std::istream_iterator<float>(fileHandle), 
       std::istream_iterator<float>(), 
       std::back_inserter(vect)); 
} 

与看起来像

v 0.000000 0.000000 1.000000 
v 1.000000 0.000000 1.000000 
... 

调试它一个文件,它似乎在第一copy呼叫推动花车(整行)到载体。这实际上很好,除了它似乎冻结我的文件迭代器在下一行的'v'。 fileHandle >> id;行和copy调用不会将文件迭代器从该点向前移动,从而创建无限循环。仅使用1 copy调用创建了相同的结果。

我在做什么错?

回答

4
#include<iostream> 
#include<fstream> 
#include<iterator> 
#include<vector> 

// it is a good idea to create an structure to hold the data you will 
// be working with. In this case I am creating a bare-bones struct 
// containing a single data element 
struct entry { 
    double data[3]; 
}; 

// when you have an structure, you can overload the >> operator; this 
// will allow you to simplify later calls (as you will see below). In 
// this case, because your data file contains a "dummy" character I 
// use a dummy string. Notice that the return type is bool, and it 
// means "I was able to read what you wanted me to read", in this case 
// a line with one string and three doubles (because the type of each 
// e.data[k] is "double") 
bool operator>>(std::istream& is, entry& e) { 
    std::string dummy; 
    return is>>dummy>>e.data[0]>>e.data[1]>>e.data[2]; 
} 


int main() { 
    // create a vector to hold the entries (notice that "entry" is the 
    // data type you created above) 
    std::vector<entry> entries; 

    { // the bracket on the left will provide a "scope" for the "fp" 
    // variable. When the scope ends, "fp" will be automatically 
    // destroyed. For "fp" that means that the "close()" method will 
    // be called upon destruction, and you don't need to worry about 
    // ensuring that your files are closed (to lear more about this 
    // google for RAII) 

    std::ifstream fp("test.txt"); 
    // the iterators DO NOT REQUIRE A LOOP (they "provide" the loop; 
    // they are used precisely to avoid coding the loop) 

    std::copy(std::istream_iterator<entry>(fp), 
       std::istream_iterator<entry>(), 
       std::back_inserter<std::vector<entry>>(entries)); 
    // notice that the back inserter will insert "entry" types into 
    // the "entries" vector as long as it can continue reading them 
    // (that is, as long as ">>" continues to return "true" 

    } // the bracket on the left is finishing the scope I talked about 
    // above. Past this point fp no longer exists, and the file has 
    // been closed 

    // off you go - you have your vector full of "entry" instances which 
    // you can use normally 
    std::cout<<"read "<<entries.size()<<" entries: "<<std::endl; 
    for(auto e:entries) { 
    std::cout<<e.data[0]<<", "<<e.data[1]<<", "<<e.data[2]<<std::endl; 
    } 

    return 0; 
} 

我编译使用gcc 4.7.2使用此源代码:

g++ example.cpp -std=c++11 

有了完全一样,你只要将文件(我称之为“的test.txt”)我得到以下几点:

read 2 entries: 
0, 0, 1 
1, 0, 1 
+0

哦,这就是拷贝线是如何工作的。 – slicedtoad 2013-05-10 19:00:08

+0

感谢您的帮助,评论非常有用。我实际上使用虚拟字符作为通过switch语句的标识符,但我想我可以弄清楚如何进行适当的更改。 – slicedtoad 2013-05-10 19:12:27

+0

你可以用所需的行为增加“结构”,并把所有的逻辑放在“操作员>>”中 - 你首先阅读“dummy”(你可以称之为“flag”,或者不是虚拟的东西),而“标记“每个条目。 – Escualo 2013-05-10 19:16:54

2

以下是使用Boost Spirit的简单方法。

这借给你难以置信的灵活性,因为它定义了一个实际的语法在线:

('v' >> qi::float_ >> qi::float_ >> qi::float_) % qi::eol, 

下面是完整的程序:

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/karma.hpp> 

namespace qi = boost::spirit::qi; 

int main() 
{ 
    std::cin >> std::noskipws; 
    boost::spirit::istream_iterator f(std::cin), l; 

    std::vector<float> vect; 

    bool ok = qi::phrase_parse(f,l, // std::cin 
      ('v' >> qi::float_ >> qi::float_ >> qi::float_) % qi::eol, 
      qi::blank, // ignore any whitespace separators 
      vect);  // keep appending to a vector 
      // (this could easily be a vector of structs containing 3 floats) 

    if (ok) 
    { 
     std::cout << "parse success\n"; 

     // only for verification output: 
     using namespace boost::spirit::karma; 
     std::cout << "parsed vect: \n" << format_delimited(columns(3) [ *auto_ ], ' ', vect) << "\n"; 
    } 
    else std::cerr << "parse failed: '" << std::string(f,l) << "'\n"; 

    if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n"; 
    return ok; 
}