Самый простой способ получить строку, когда данные поступают кусками? - PullRequest
2 голосов
/ 05 февраля 2011

Я использую win32 ReadFile для чтения из канала дочернего процесса. Это дает мне куски символов за раз и размер каждого чанка, но у них могут быть или не быть новые строки. Я хочу обрабатывать вывод построчно. Какой самый простой способ сделать это?

Я думал о добавлении каждого куска к string, и в конце, используя stringstream, чтобы обрабатывать его построчно, но я хотел бы сделать это по мере поступления данных. Я предполагаю хитрость есть, как и где я должен обнаружить окончание новой строки? Если только streamreader s getline ничего не вернуло, когда разделитель не найден ...

Ответы [ 3 ]

1 голос
/ 05 февраля 2011

Добавляйте в строку, пока не встретите символ новой строки или конец данных.Затем у вас есть строка в строке, обработайте ее, пустую строку и повторите.Причина использования строки: вы не знаете, какова может быть длина строки, а строка выполняет перераспределение и т. Д. По мере необходимости.

Особый случай: конец данных, в котором ранее ничего не былодолжно быть не в строке, игнорируется.

Приветствия & hth.

0 голосов
/ 05 февраля 2011

Вы можете расширить std::basic_streambuf и внедрить xsputn, чтобы он сохранял данные во внутреннем буфере и обнаруживал новые строки или выполнял любую необходимую обработку. Если вы хотите обрабатывать только полные строки, при обнаружении вы можете увеличить размер буфера до std::queue до новой строки и удалить соответствующую часть из буфера. Вам нужно будет также реализовать overflow. Например:

template<typename CharT, typename Traits = std::char_traits<CharT> >
class line_streambuf : public std::basic_streambuf<CharT, Traits> {
public:
    typedef CharT                           char_type;
    typedef Traits                          traits_type;
    typedef std::basic_string<char_type>    string_type;
    typedef typename string_type::size_type size_type;
    typedef typename traits_type::int_type  int_type;
    line_streambuf(char_type separator = '\n') : _separator(separator) {}
    virtual ~line_streambuf() {}
    bool getline(string_type& output) { /* pop from the queue and return */ }
protected:
    virtual int_type overflow(int_type v) {
        if (v == _separator) {
            _processed.push(_buffer);
            _buffer.erase(_buffer.begin(), _buffer.end());
        } else {
            _buffer += v;
        }
        return v;
    }
    virtual std::streamsize xsputn(const char_type* p, std::streamsize n) {
        _buffer.append(p, p + n);
        while (true) {
            // The 1st find could be smarter - finding only after old_length+p
            size_type pos = _buffer.find(_separator);
            if (pos == string_type::npos)
                break;
            _processed.push(string_type(_buffer.begin(), _buffer.begin()+pos));
            _buffer.erase(_buffer.begin(), _buffer.begin() + pos + 1);
        }
        return n;
    }
private:
    char_type _separator;
    string_type _buffer;
    std::queue<string_type> _processed;
};

ПРИМЕЧАНИЕ : крайне непроверенный код. Дайте мне знать, если вы обнаружите проблему, или не стесняйтесь редактировать.

0 голосов
/ 05 февраля 2011

Что я могу придумать, так это использовать буфер, в котором хранятся куски, приходящие к вам, вы знаете размер через lpNumberOfBytesRead, поэтому для каждого чанка вы проверяете, содержит ли он символ новой строки / s, и если он есть, вы выводите все буферизованные символы до символа новой строки, затем начинайте буферизацию до тех пор, пока не получите другой блок с символами новой строки и т. д.

Некоторые псевдокоды могут выглядеть следующим образом:

w_char buffer[BUFFER_SIZE]; // enough for few chunks (use new to allocate dynamic memory)
ReadLine(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
if (w_char has new_line_character) {
    process_whole_line(); // don't forget to clear up the buffer
}
...