2013-11-22 44 views
0

我试图解析/proc/partitions文件。流>>最后一行读两次

major minor #blocks name 

    8  0 976762584 sda 
    8  1 99998720 sda1 
    8  2   1 sda2 
    8  3 103561216 sda3 
    8  4 291514368 sda4 
    8  5 1998848 sda5 

这是我机器中的/ proc /分区文件。

#include <boost/cstdint.hpp> 
#include <fstream> 
#include <boost/algorithm/string/trim.hpp> 
#include <boost/format.hpp> 

int main(){ 
    std::ifstream proc_partitions_stream("/proc/partitions"); 
    boost::int32_t disc_partition_line_count = -2; //-1 for headers, -1 for the empty line 
    //so counter is 0 when it tries to read the real entries 
    while(!proc_partitions_stream.fail()){ 
    if(disc_partition_line_count >= 0){ 
     boost::uint16_t major, minor; 
     boost::uint64_t blocks; 
     std::string label; 
     proc_partitions_stream >> major >> minor >> blocks >> label; 
     std::cout << boost::format("%1% %2% %3% %4%") % major % minor % blocks % label << std::endl; 
     boost::algorithm::trim(label);  
    }else{ 
     std::string line; 
     std::getline(proc_partitions_stream, line); 
    } 
    ++disc_partition_line_count; 
    } 
    return 0; 
} 

但它读取最后一行两次这里是程序

8 0 976762584 [sda] 
8 1 99998720 [sda1] 
8 2 1 [sda2] 
8 3 103561216 [sda3] 
8 4 291514368 [sda4] 
8 5 1998848 [sda5] 
8 5 1998848 [] << read the last line TWICE but didn't read the label 
+2

你永远不会检查你的输入提取成功。而你的循环并不比在while-conditional中检查eof更好[[这几乎是*总是*错]](http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-循环条件被认为是错误的) – WhozCraig

回答

3

因为你的while循环的条件是错误的,你你读,你应该测试失败之前测试失败之后你看过。更好的办法是测试getline的回报。

+0

但是然后我必须在getline和提取值之后创建一个stringstream或者按空间拆分。我应该在每一个'stream >> v'操作之后检查吗?为什么它会读两行?它应该总是前进。但它正在倒退到最后一行的开始。 –

+1

@NeelBasu它不会读两次。它不会通过不成功的读取覆盖变量值。所以你只是*处理它们两次。而且你不必测试每个'>>';测试最后一个就足够了。 – Angew

+0

雅谢谢。我现在明白了。如果我将它们初始化为0,那么它不会再次填充之前的值。 –

2

我将它改写到更多的东西,如:

#include <boost/cstdint.hpp> 
#include <fstream> 
#include <boost/algorithm/string/trim.hpp> 
#include <boost/format.hpp> 

int main(){ 
    std::ifstream proc_partitions_stream("/proc/partitions"); 

    for (int i=0; i<2; i++) 
     proc_partitions_stream.ignore(max_len, '\n'); 

    boost::uint16_t major, minor; 
    boost::uint64_t blocks; 
    std::string label; 
    while (proc_partitions_stream >> major >> minor >> blocks >> label) { 
     std::cout << boost::format("%1% %2% %3% %4%") % major % minor % blocks % label << "\n"; 
     //boost::algorithm::trim(label); // was present, but non-functional? 
    } 
    return 0; 
} 

另外,定义了一个小的类来表示一个盘分区,超载运营>>和< <为,还有一个小功能从一个IStream跳过线:

class partition { 
    boost::uint16_t major, minor; 
    boost uint64_t blocks; 
    std::string  label; 
public: 
    friend std::istream &operator>>(std::istream &is, partition &p) { 
     return is >> major >> minor >> blocks >> label; 
    } 

    friend std::ostream &operator<<(std::ostream &os, partition const &p) { 
     return os << boost::format("%1% %2% %3% %4%") % major % minor % blocks % label; 
    } 
}; 

std::istream &skiplines(std::istream &is, unsigned count) { 
    unsigned max_len = something; // see below 
    return is.ignore(max_len, '\n'); 
} 

然后在main你得到的也类似:

if (!skiplines(2)) { 
    std::cerr << "Error!\n"; 
    return 1; 
} 

std::copy(std::istream_iterator<partition>(proc_partitions_stream), 
      std::istream_iterator<partition>(), 
      std::ostream_iterator<partition>(std::cout, "\n")); 

至于什么值用于max_len去:有不少人使用std::numeric_limits<std::streamsize>::max()。作为一个规则,我更喜欢比较小的东西。在这种情况下它可能没有什么区别(机会或格式错误的输入很小),但是如果你只是想跳过一条线,最好将它限制在某条线的一半以上合理。如果你只是告诉用户有问题,那么在你这样做之前,没有理由浪费他们的时间等待你阅读千兆字节的垃圾。