Войти второй раз в тот же поток
От: SergH Россия  
Дата: 26.08.08 11:25
Оценка:
Привет!

Есть поток std::istream
Есть xml-парсер подвида SAX, который принимает этот поток на вход.

Проблема в том, что есть несколько видов xml-файлов, и хочется написать для каждого из них свой обработчик, а не пихать всю логику в один большой. Что за файл обрабатывается, можно понять по первому тегу. Т.е. надо распарсить файл до первого тега, прочитать тег, сказать "ага!", и потом, зная тип файла, парсить его заново.

Вопрос в том, как реализовать это "заново". Для этого нужно как-то отмотать поток данных назад... Про метод putback я знаю, но в данном случае я не контролирую чтение, читает парсер, я не знаю, что он там прочёл.

Есть какие-то красивые варианты? Копировать пока не хочется, там может быть довольно много. Даже "копировать первые несколько килобайт" пока не очень хочется.
Делай что должно, и будь что будет
Re: Войти второй раз в тот же поток
От: Кодт Россия  
Дата: 26.08.08 11:44
Оценка:
Здравствуйте, SergH, Вы писали:

SH>Есть поток std::istream


Наверное, всё-таки ifstream, или ты с консоли эти файлы читаешь?
ifstream ifs (the_filename);
read_till_first_tag(ifs);
ifs.rdbuf()->seekpos(0); // перемотал на начало
read_whole_file(ifs);
Перекуём баги на фичи!
Re[2]: Войти второй раз в тот же поток
От: SergH Россия  
Дата: 26.08.08 11:53
Оценка:
Здравствуйте, Кодт, Вы писали:

SH>>Есть поток std::istream

К>Наверное, всё-таки ifstream, или ты с консоли эти файлы читаешь?

Я их из сети качаю. И иногда попутно пропускаю через разархивирующий поток.

К>
К>ifstream ifs (the_filename);
К>read_till_first_tag(ifs);
К>ifs.rdbuf()->seekpos(0); // перемотал на начало
К>read_whole_file(ifs);
К>


Но надо попробовать, вдруг прокатит
Делай что должно, и будь что будет
Re: Войти второй раз в тот же поток
От: ilnar Россия  
Дата: 26.08.08 12:00
Оценка:
"нельзя войти в одну реку дважды."

не для всех типов поддерживаются произвольные перемещения.
Re[2]: Войти второй раз в тот же поток
От: SergH Россия  
Дата: 26.08.08 12:07
Оценка:
Здравствуйте, ilnar, Вы писали:

I>"нельзя войти в одну реку дважды."

I>не для всех типов поддерживаются произвольные перемещения.

Да. Но мне не надо произвольное. Мне надо всего лишь "запомнить" состояние, прочитать сколько-то символов, а потом снова к нему вернуться. Для этого достаточно иметь буфер, по идее это не так сложно.. Я даже свой буфер могу предоставить. Но вот перспектива прикручивать его к istream-у через создание своего класса, реализующего istream меня не радует.
Делай что должно, и будь что будет
Re[2]: Войти второй раз в тот же поток
От: SergH Россия  
Дата: 26.08.08 12:09
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Наверное, всё-таки ifstream, или ты с консоли эти файлы читаешь?

К>
К>ifstream ifs (the_filename);
К>read_till_first_tag(ifs);
К>ifs.rdbuf()->seekpos(0); // перемотал на начало
К>read_whole_file(ifs);
К>


увы
#include <sstream>
#include <string>
#include <iostream>

int main()
{
    std::stringstream ss;
    ss << "hello, world!";

    std::string s;
    ss >> s;
    std::cout << s;

    ss.rdbuf()->seekpos(0); // error C2248: 'std::basic_stringbuf<_Elem,_Traits,_Alloc>::seekpos' : cannot access protected member declared in class 'std::basic_stringbuf<_Elem,_Traits,_Alloc>'
    ss >> s;

    std::cout << s;
}
Делай что должно, и будь что будет
Re: Войти второй раз в тот же поток
От: rg45 СССР  
Дата: 26.08.08 13:06
Оценка: +1
Здравствуйте, SergH, Вы писали:

SH>Привет!


SH>Есть поток std::istream

SH>Есть xml-парсер подвида SAX, который принимает этот поток на вход.

SH>Проблема в том, что есть несколько видов xml-файлов, и хочется написать для каждого из них свой обработчик, а не пихать всю логику в один большой. Что за файл обрабатывается, можно понять по первому тегу. Т.е. надо распарсить файл до первого тега, прочитать тег, сказать "ага!", и потом, зная тип файла, парсить его заново.


SH>Вопрос в том, как реализовать это "заново". Для этого нужно как-то отмотать поток данных назад... Про метод putback я знаю, но в данном случае я не контролирую чтение, читает парсер, я не знаю, что он там прочёл.


SH>Есть какие-то красивые варианты? Копировать пока не хочется, там может быть довольно много. Даже "копировать первые несколько килобайт" пока не очень хочется.


Я бы строил систему таким образом, что бы вообще избежать повторного парсинга. Схематично так: парсер верхнего уровня парсит корневой тег, при успешном распознавании создает экземпляр соответствующего класса, в который запихивает внутренности корневого тега. В этом виде этот объект скармливается обработчику нижнего уровня, который уже допарсивает внутренности и выполняет необходимую обработку. Обработчики нижнего уровня также могут иметь подчиненные обработчики. Таким образом можно конструировать иерархии обработчиков.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: Войти второй раз в тот же поток
От: SergH Россия  
Дата: 26.08.08 13:12
Оценка:
Здравствуйте, rg45, Вы писали:

R>Я бы строил систему таким образом, что бы вообще избежать повторного парсинга. Схематично так: парсер верхнего уровня парсит корневой тег, при успешном распознавании создает экземпляр соответствующего класса, в который запихивает внутренности корневого тега. В этом виде этот объект скармливается обработчику нижнего уровня, который уже допарсивает внутренности и выполняет необходимую обработку. Обработчики нижнего уровня также могут иметь подчиненные обработчики. Таким образом можно конструировать иерархии обработчиков.


Так и было. А потом содержимое разных типов файлов разошлось немного дальше, и теперь у разных обработчиков разные интерфейсы... Всегда передавать все обработчики не хочется. Передавать один, с "большим" интерфейсом тоже. Видимо, всё-таки буду делать свой поток.
Делай что должно, и будь что будет
Re[3]: Войти второй раз в тот же поток
От: igna Россия  
Дата: 26.08.08 15:11
Оценка: 14 (1)
Здравствуйте, SergH, Вы писали:

SH>    ss.rdbuf()->seekpos(0); // error C2248: 'std::basic_stringbuf<_Elem,_Traits,_Alloc>::seekpos' : cannot access protected


    ss.seekg(0);


Или

    std::stringstream::pos_type pos = ss.tellg();
    ss >> s;
    std::cout << s;

    ss.seekg(pos);
Re[4]: Войти второй раз в тот же поток
От: SergH Россия  
Дата: 28.08.08 01:49
Оценка:
Здравствуйте, igna, Вы писали:

I>
I>    ss.seekg(0);
I>


Эх, отвлекли на другую задачу, к этому вернусь только через недельку. Со stringstream-ом действительно работает, а вот с самодельным (не мной) потоком, реализующим unzip — надо проверить. Но всё равно большое спасибо!
Делай что должно, и будь что будет
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.