2013-11-22 66 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()。作爲一個規則,我更喜歡比較小的東西。在這種情況下它可能沒有什麼區別(機會或格式錯誤的輸入很小),但是如果你只是想跳過一條線,最好將它限制在某條線的一半以上合理。如果你只是告訴用戶有問題,那麼在你這樣做之前,沒有理由浪費他們的時間等待你閱讀千兆字節的垃圾。