| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Java: Общие вопросы > Парсинг длинного файла |
| Автор: Stampede 28.4.2005, 01:01 |
| Взываю к коллективной мудрости. Имеется задача: есть текстовые документы некоего фиксированного формата (финансовые отчеты). Их нужно парсить: определять по заданным признакам начало и конец отдельного документа (например, инвойса), а затем внутри документа выделять, опять же по заданным признакам, определенные поля (номер счета, сумму, дату и пр.), и вытягивать их значения. Потом вся эта выуженная информация куда-нибудь сохраняется. Признаки наяала и конца документа, а также отдельных его полей, задаются в виде регулярных выражений. Если бы можно было зачитать весь файл целиком в память, то всех делов было бы примерно минут на пять То есть я вижу себе такое как бы ползущее окно, которое двигается вдоль файла и сканирует его на предмет начала/конца документа. Когда документ полностью детектирован, мы проходим по нему второй раз и определяем значения полей. Тут, казалось бы, тоже нет ничего трудного, но есть ряд нюансов. Во-первых, побуферный парсинг здесь не подходит, так как искомая строка может оказаться разорванной на границе буфера, и регекспом не обнаружится. Во-вторых, даже один отдельный документ может быть достаточно большим, поэтому и внутри него парсить нужно будет тоже не в памяти. Из хороших моментов: известно, что искомая строка не может перекрывать раздел страниц, то есть можно безопасно ориентироваться на символ конца страницы как на сигнал к закрытию текущего буфера. Впоследствии этот же механизм ползущего окна хотелось бы использовать в гуевом приложении для отображения файла в окне прокрутки без загрузки в память целиком. На ум приходит что-то вроде смапленной на файл виртуальной строки (условно) бесконечной длины, но как это лучше реализовать - пока не соображу. У кого какие будут идеи? ЗЫ. Блин, ошибся топиком. Прошу перенести в Java: Общие вопросы. Спасибо. |
| Автор: Domestic Cat 28.4.2005, 01:35 |
| Может этим: http://java.sun.com/j2se/1.4.2/docs/api/java/nio/MappedByteBuffer.html правда дальше я не думал, но вроде как подходит, есть asCharBuffer и проч. |
| Автор: Zandr 28.4.2005, 09:39 | ||
Если регекспы, то обрати внимание, что они ищут не в String'ах или StringBuffer'ах, а в CharSequence. CharSequece это интерфейс. Можешь попробовать реализовать что-нить типа:
На счет быстродействия ничего сказать не могу - как реализуешь. |
| Автор: Stampede 28.4.2005, 10:32 |
| Котъ, Zandr - спасибо за идеи. Будет чем заняться завтра на работе |
| Автор: Stampede 29.4.2005, 01:04 |
| Докладаю. Сижу и тащусь как удав по пачке дуста. Работает - проооосто как песТня. Всего делов было - несколько строк преобразований типа RandomAccessFile -> FileChannel -> MappedByteBuffer -> (Charset, CharsetDecoder) -> CharBuffer. Фсе! Далее абстрагируемся от подлежащего (underlying) файла и регекспим как обычную строку! Спасибо, отцы! Да здравствует Винградовка! ЗЫ. Хотел не радостях вам плюсов надавать - не пущает. Маладой, говорит, ишшо. Это я-то молодой? Хе-хе ... Котъ, ну хоть Zandr'у влепи одного - от имени, тыкскыть, и по поручению благодарной общественности |
| Автор: Domestic Cat 29.4.2005, 01:06 |
| Ура так сказать! Тащимся вместе с тобой ! |
| Автор: Zandr 29.4.2005, 06:43 | ||
Красиво |
| Автор: Stampede 29.4.2005, 19:54 | ||
Любознательным на заметку, дополнение:
Красиво-то оно может и красиво, но я вот сейчас попробовал получить буфер напрямую, без преобразований через CharDecoder - через метод asCharBuffer(), который предлагал Котъ, так оно теперь в 5 (пять!) раз быстрее мослает. Но, блин, нет в мире совершенства. Это работает только с текстами в ASCII. Если нужна другая кодировка, придется все равно использовать CharDecoder. А что делать? Да, кстати, с седьмым плюсом тебя? |
| Автор: Stampede 30.4.2005, 00:43 | ||
| Блин, погорячился. Вношу поправку. Короче, по производительности никакого выигрыша почти нет. Просто я не заметил, что в варианте с asCharBuffer() содержимое интерпретировалось неправильно, поэтому регекспы ничего не находили, и в результате получалось быстрее. Нам, однако, такой хоккей не нужен. Нам нужно не быстро, а нам нужно, чтобы правильно. Так вот, в ходе экспериментов выяснилось, что по дефолту тот буфер, который возвращает asCharBuffer() (какой-то внутренний класс DirectByteBuffer), поддерживает только кодировку UTF-16. Скорость обработки файла при этом сопостовима со скоростью в варианте с CharsetDecoder (правда, там сам исходный файл в UTF-16 в два раза длиннее, так что вроде бы работает быстрее, но нам ведь нужно ехать, а не шашечки Поиски способа сменить дефолтную кодировку ни к чему не привели, так что, как говорится, не выеживайтесь, Иван Иваныч, слушайте вашу любимую песню "Валенки" На случай, если у кого-то возникнет аналогичная задача, привожу код манипуляций:
|
| Автор: Zandr 4.5.2005, 07:05 | ||
Вот не совсем понятное место:
Не прошарил как работает этот метод... Он не пытается сразу весь файл перекачать в память? Или как задумано дает char'ы что называется on demand? |