| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Java: Общие вопросы > Как читать XML (SAX) частями? |
| Автор: Sardar 7.2.2006, 13:17 |
| Есть масса логов, пишуться java.util.logging через XMLFormatter. Получаю длиннющую (в реале и на пол гига, не шучу) простыню, которую нужно уметь быстро просматривать. При старте нужно зачитать первую сотню записей, показать, дабы юзер не думал что прога тормозит. Отдельный тред пробегаеться по всему файлу, строит графическую полоску (удобно видеть где что в логе) и индексы. Как только индекс [номер записи : позиция в файле] доступно, можно спокойно скролить и прыгать в любое место. Вопрос: как реализовать быстрые переходы по файлу, альтернатива reset/skip? Или есть у кого результаты тестов этих операций под разными платформами (интересует RHE Linux, Solaris)? Или просто совет кто уже делал подобное? В итоге пишу Reader -> InputSource -> XMLReader.parse, так, что последний не должен заметить что прыгаем по файлу, как будто одна длинная простыня. Название топу дал такое, т.к. вопрос больше как сабж. лучше сделать, может и не нужно вовсе свой Reader писать |
| Автор: Stampede 7.2.2006, 19:03 | ||
Я тоже сперва об этом подумал, но потом прикинул, что оно скорее всего не подойдет: если регекспу пофиг с какого места парсить, то XML ридеру таки нужен контекст. Другое дело, что можно при первом проходе SAX парсером отлавливать начало и конец уаждой отдельной записи и заносить эту инфу в таблицу. А потом по мере скроллинга восстанавливать по номеру записи ее смещение, считывать из RandomAccessFile полный текст соответствующего ей XML элемента, и тогда уже добирать всю остальную инфу, относящуюся к записи, путем парсинга этого элемента. У меня кстати примерно на таком принципе построен вьюер тех здоровых файлов, про которые я писал в упомянутом топике. Причем не просто вьюер, а вьюер с подсветкой найденных элементов. И работает, кстати, весьма шустро. Так что есть смысл попробовать. |
| Автор: LSD 7.2.2006, 21:41 |
| Стандартный XML парсер так работать не сможет конечно, так как не любую структуру можно так распарсить. Но тут структура XML очень простая, и это можно использовать. В принципе можно написать свой Reader который бы позволил парсить файл с произвольной позиции (есть пара идей). Sardar подкинь структуру XML, по возможности в виде схемы. |
| Автор: Sardar 7.2.2006, 22:25 |
| Пишеться через java.util.logging.XMLFormatter, http://java.sun.com/j2se/1.5.0/docs/guide/logging/overview.html#2.4 и http://java.sun.com/j2se/1.5.0/docs/guide/logging/overview.html#3.0 Для любого XML конечно нужен контекст, но логи это всё таки поток обьектов без навороченной структуры. Отсюда идея пока так: [стрим из файла] -> {мой стрим/ридер с методом seek} -> [XMLReader] -> {логика} -> {анализатор} //в фигурных моё, в квадратных классы из стандартной либы Т.е. оборачиваю бычный стрим своим wrapper'ом, что (пока) методами reset/skip будет свободно перемещаться по стриму. Памяти кушать могут мало, потому хранить прочитанное долго не буду, стрим должен поддерживать reset(). Логика делает что нужно для задачи, одновременно посылает в анализатор уведомления [начался требуемый обьект, закончился требуемый обьект]. Таким образом должен создаваться индекс с позициями обьектов. Если пользователь решит скролить назад, то позиции имеем, если вперёд, то нужно прочитать на перёд обновляя индекс. Идея не плохая, но что то не понял как узнать на каком символе сейчас находимся, SAX парсер не даёт контекстной информации... Интерфейс Locator есть, но всё натыкаюсь что "пользователь должен имплементировать сию функциональность". Может плохо искал... Отсюда проблема: как узнать на каком символе сейчас находимся получая SAX события? Если парсер ещё и буфферизует сам символы или события на перёд, то идее конец... придёться брать другой SAX парсер. Вроде апачи что то мощное имеют, все кто знаком с альтернативными парсерами откликнитесь |
| Автор: LSD 8.2.2006, 12:30 | ||||
FileInputStream не поддерживает mark(), только BufferedInputStream который делает это все за счет кеша в памяти. Я честно говоря не понял зачем тебе понадобилось знать на каком символе сейчас находимся получая SAX события, что это тебе даст? Все равно парсер нельзя остановить или сказать ему парсить обратно. Я бы сделал так: пишем свой java.io.Reader, которому указываем смещение и количество байт которое надо прочитать. Наш Reader читает файл начиная с этого смещения и ищет открывающий тег (<record>) как только находит выдает:
и далее все что прочтет пока не превысит лимит прочитанных байт, тогда ждет закрывающий тег (</record>) и в дополнение к нему выдает закрывающий </log>. При этом мы можем использовать любой парсер хоть SAX хоть DOM. |
| Автор: Sardar 8.2.2006, 13:03 |
| А мне и не нужно останавливать парсер, он вообще не знает о переходах, получает инфу как одну большую простыню. Ага, говорим об одном и том же, просто я задумался чуть дальше. Как сказать своему ридеру, что с текущей позиции начался новый обьект? Ридер должен тогда занести позицию в индекс [порядковый номер обьекта => смещение], далее прыгать можно сразу пользуя порядковый номер обьекта. Проблемы:
Млин, а начиналось как весьма простая задача... |
| Автор: LSD 11.2.2006, 13:37 | ||
| Значита так: С Locator я разобрался, там все просто как 3 копейки. Когда ты задаешь свой DefaultHandler устанавливает ему свой Locator (если конечно парсер поддерживает такую фишку). Парсер из JDK 1.5 поддерживает, юзать так:
Правда это мало помогает, т.к. там идут координаты в строка/символ, а для Reader надо в байтах. Парсер читает столько данных сколько есть в потоке. Если скармливать ему по одному символу, то начало/конец тега получим как только он получит последний символ. Теперь к Reader-у считать данные из произвольной позиции файла и отдать их не проблема, вопрос только в этих позициях. Можно хранить два массива long в одном номер записи, в другом смещение в байтах от начала файла. Но тут вылезает вопрос памяти, если считать, что файл имеет размер 1Гб, а размер одной записи 300 байт, то у нас будет около 3 500 000 записей и на это дело надо будет 58Мб. Так что придется хранить каждую 16 или даже 32 запись. Но это в принципе не проблема, проблема в том как заполнить этот индекс. |