2014-01-18 97 views
2

內的管我有以下問題:實現C/C++程序

我已經寫了一個簡單unzipper,其unzippes。廣州文件相,每行(/ n)時,由另一個進程處理。所以,在shell中,我可以輸入:

解壓器文件|程序

這兩個程序都是C/C++編碼的。

有誰知道是否和如何我能實現這個「管」(|)一個C/C++程序中,這樣我可以做這樣的事情多線程例如...

在我的特別情況下,重要的是保持新的結構不變,這就是爲什麼我使用管道。 gz文件太大而不能保存在整個內存中。

+0

你不需要管的線來處理輸入線。只需逐行閱讀。那麼可以通過使用線程或協程來簡化控制結構(例如,在20世紀60年代爲Algol編譯器完成的IIRC)。 –

+0

答案取決於您的操作系統。我建議添加一個「linux」或「osx」或「windows」標籤(或「solaris」或者「posix」或其他),具體取決於你的意思。 – Nemo

+0

所以基本上你想把2個程序合併成1個?您使用'pipe'系統調用來創建管道。一個線程解壓縮文件並寫入管道;另一個線程讀取管道並執行任何操作。無論你通過這個獲得什麼是一個開放的問題。 – Duck

回答

1

在編程方面一般有生成器;在C++中,我們傾向於將它們看作輸入迭代器但是,關注點仍然是相同的:很像一個管道,它大約是拉驅動的生產。因此,您可以圍繞生產者(最好具有輸入迭代器的接口)和消費者的想法來重組您的程序,並且消費者會在當時要求輸入一行,生產者會懶惰地拿出來。

對於必要的界面很好的指導,我推薦古老的SGI STL網站:這裏是InputIterator的概念。

對於一個簡單的例子,假設我們沒有處理解壓和剛讀上線,每線的基礎文件:

class LineIterator: public std::iterator<std::input_iterator_tag, 
             std::string const> 
{ 
public: 
    // Default Constructible 
    LineIterator(): stream(nullptr) {} 

    explicit LineIterator(std::istream& is): stream(&is) { this->advance(); } 

    // Equality Comparable 
    friend bool operator==(LineIterator const& left, LineIterator const& right) { 
     return left.stream == right.stream 
      and left.buffer == right.buffer 
      and left.currentLine == right.currentLine; 
    } 

    friend bool operator!=(LineIterator const& left, LineIterator const& right) { 
     return not (left == right); 
    } 

    // Trivial Iterator (non mutable) 
    pointer operator->() const { return &currentLine; } 

    reference operator*() const { return currentLine; } 

    // Input Iterator 
    LineIterator& operator++() { 
     this->advance(); 
     return *this; 
    } // operator++ 

    LineIterator operator++(int) { 
     LineIterator tmp(*this); 
     ++*this; 
     return tmp; 
    } // operator++ 

private: 
    void advance() { 
     // Advance a valid iterator to fetch the next line from the source stream. 
     static LineIterator const SingularValue; 

     assert(*this != SingularValue and "Cannot advance singular iterator"); 
     // Note: in real life, I would use std::getline... 
     // ... but it would not showcase the double-buffering model 
     // required to solve the OP problem (because of decoding) 

     // We use double-buffering, so clear current and swap buffers 
     currentLine.clear(); 
     swap(buffer, currentLine); 

     // Check if we found some new line or not 
     size_t const nl = currentLine.find('\n'); 

     // If we found one already, preserve what's after in the buffer 
     // as we only want to expose one line worth of material. 
     if (nl != std::string::npos) { 
      if (nl == currentLine.size()) { return; } // nothing to preserve 

      buffer.assign(currentLine.begin() + nl + 1, currentLine.end()); 
      currentLine.erase(currentLine.begin() + nl + 1, currentLine.end()); 
      return; 
     } 

     // If we did not, then we need to pump more data into the buffer. 
     if (not stream) { return; } // Nothing to pump... 

     static size_t const ReadBufferSize = 256; 
     char input[ReadBufferSize]; 

     while (stream->read(input, ReadBufferSize)) { 
      if (this->splitBuffer(input, ReadBufferSize)) { break; } 
     } 

     // We end up here either if we found a new line or if some read failed. 
     // If the stream is still good, we successfully found a new line! 
     if (*stream) { return; } 

     // Otherwise, the stream is no good any longer (it dried up!) 
     // but we may still have read some little things from it. 
     this->splitBuffer(input, stream->gcount()); 

     stream = SingularValue.stream; // stream dried up, 
             // so reset it to match singular value. 
    } // advance 

    bool splitBuffer(char const* input, size_t const size) { 
     // Split input at the newline character, the first chunk ends 
     // up in currentLine, the second chunk in buffer. 
     // Returns true if a newline character was found, false otherwise. 

     // Check if we finally found a new line 
     char const* const newLine = std::find(input, input + size, '\n'); 

     // If we did not, copy everything into currentLine and signal it. 
     if (newLine == input + size) { 
      currentLine.append(input, size); 
      return false; 
     } 

     // If we did, copy everything up to it (including it) into currentLine 
     // and then bufferize the rest for the next iteration. 
     currentLine.append(input, newLine + 1); 
     buffer.assign(newLine + 1, input + size); 
     return true; 
    } // splitBuffer 

    std::istream* stream; 
    std::string buffer; 

    std::string currentLine; 
}; // class LineIterator 

這有點拗口的(並且是大概車......),它仍然有我們需要與STL算法,如組成它的接口:

std::ifstream file("someFile.txt"); 
std::copy(LineIterator(file), LineIterator(), std::ostream_iterator(std::cout)); 

將在同一時間(demo here)呼應的終端一個行的文件。

現在,所有你需要做的就是更換取部分(stream.read)由塊的塊讀&解壓:)

+0

好的,非常感謝你的回覆。我確實有幾個問題,因爲我不是高級的C程序員。任何人都可以解釋以下結構: – Niels

+0

class LineIterator:public std :: iterator 顯式LineIterator(std :: istream&is):stream(&is){this-> advance() ; } – Niels

+0

我不明白:構造,那裏發生了什麼。然後,朋友是什麼? – Niels