Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Парсинг длинного файла, Как лучше реализовать? 
:(
    Опции темы
Stampede
Дата 28.4.2005, 01:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 24
Всего: 144



Взываю к коллективной мудрости.

Имеется задача: есть текстовые документы некоего фиксированного формата (финансовые отчеты). Их нужно парсить: определять по заданным признакам начало и конец отдельного документа (например, инвойса), а затем внутри документа выделять, опять же по заданным признакам, определенные поля (номер счета, сумму, дату и пр.), и вытягивать их значения. Потом вся эта выуженная информация куда-нибудь сохраняется.

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

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

Во-первых, побуферный парсинг здесь не подходит, так как искомая строка может оказаться разорванной на границе буфера, и регекспом не обнаружится. Во-вторых, даже один отдельный документ может быть достаточно большим, поэтому и внутри него парсить нужно будет тоже не в памяти.

Из хороших моментов: известно, что искомая строка не может перекрывать раздел страниц, то есть можно безопасно ориентироваться на символ конца страницы как на сигнал к закрытию текущего буфера.

Впоследствии этот же механизм ползущего окна хотелось бы использовать в гуевом приложении для отображения файла в окне прокрутки без загрузки в память целиком. На ум приходит что-то вроде смапленной на файл виртуальной строки (условно) бесконечной длины, но как это лучше реализовать - пока не соображу.

У кого какие будут идеи?

ЗЫ. Блин, ошибся топиком. Прошу перенести в Java: Общие вопросы. Спасибо.


Это сообщение отредактировал(а) Stampede - 28.4.2005, 01:26


--------------------
"If you want something done right, do it yourself"
По секрету: выучить английский - реально!
PM WWW   Вверх
Domestic Cat
Дата 28.4.2005, 01:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Может этим:
http://java.sun.com/j2se/1.4.2/docs/api/ja...ByteBuffer.html
правда дальше я не думал, но вроде как подходит, есть asCharBuffer и проч.


--------------------

PM   Вверх
Zandr
Дата 28.4.2005, 09:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 433
Регистрация: 16.7.2004
Где: Новосибирск

Репутация: 9
Всего: 13



Если регекспы, то обрати внимание, что они ищут не в String'ах или StringBuffer'ах, а в CharSequence. CharSequece это интерфейс. Можешь попробовать реализовать что-нить типа:
Код

public class BigDocument implements CharSequence
{
// а здесь используешь, например, RandomAccessFile 
// в качестве поставщика данных
}

На счет быстродействия ничего сказать не могу - как реализуешь.

Это сообщение отредактировал(а) Zandr - 28.4.2005, 09:43
PM MAIL   Вверх
Stampede
Дата 28.4.2005, 10:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 24
Всего: 144



Котъ, Zandr - спасибо за идеи. Будет чем заняться завтра на работе smile



--------------------
"If you want something done right, do it yourself"
По секрету: выучить английский - реально!
PM WWW   Вверх
Stampede
Дата 29.4.2005, 01:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 24
Всего: 144



Докладаю.

Сижу и тащусь как удав по пачке дуста. Работает - проооосто как песТня. Всего делов было - несколько строк преобразований типа RandomAccessFile -> FileChannel -> MappedByteBuffer -> (Charset, CharsetDecoder) -> CharBuffer.

Фсе! Далее абстрагируемся от подлежащего (underlying) файла и регекспим как обычную строку!

Спасибо, отцы! Да здравствует Винградовка!

smile

ЗЫ. Хотел не радостях вам плюсов надавать - не пущает. Маладой, говорит, ишшо. Это я-то молодой? Хе-хе ... Котъ, ну хоть Zandr'у влепи одного - от имени, тыкскыть, и по поручению благодарной общественности smile


Это сообщение отредактировал(а) Stampede - 29.4.2005, 01:10


--------------------
"If you want something done right, do it yourself"
По секрету: выучить английский - реально!
PM WWW   Вверх
Domestic Cat
Дата 29.4.2005, 01:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Ура так сказать! Тащимся вместе с тобой ! smile smile smile


--------------------

PM   Вверх
Zandr
Дата 29.4.2005, 06:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 433
Регистрация: 16.7.2004
Где: Новосибирск

Репутация: 9
Всего: 13



Цитата
FileChannel -> MappedByteBuffer -> (Charset, CharsetDecoder) -> CharBuffer

Красиво smile
PM MAIL   Вверх
Stampede
Дата 29.4.2005, 19:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 24
Всего: 144



Любознательным на заметку, дополнение:

Цитата(Zandr @ 29.4.2005, 06:43)
FileChannel -> MappedByteBuffer -> (Charset, CharsetDecoder) -> CharBuffer

Красиво


Красиво-то оно может и красиво, но я вот сейчас попробовал получить буфер напрямую, без преобразований через CharDecoder - через метод asCharBuffer(), который предлагал Котъ, так оно теперь в 5 (пять!) раз быстрее мослает.

Но, блин, нет в мире совершенства. Это работает только с текстами в ASCII. Если нужна другая кодировка, придется все равно использовать CharDecoder. А что делать?

Да, кстати, с седьмым плюсом тебя? smile (tnx, AntonSaburov)


PM WWW   Вверх
Stampede
Дата 30.4.2005, 00:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 24
Всего: 144



Блин, погорячился. Вношу поправку.

Короче, по производительности никакого выигрыша почти нет. Просто я не заметил, что в варианте с asCharBuffer() содержимое интерпретировалось неправильно, поэтому регекспы ничего не находили, и в результате получалось быстрее. Нам, однако, такой хоккей не нужен. Нам нужно не быстро, а нам нужно, чтобы правильно.

Так вот, в ходе экспериментов выяснилось, что по дефолту тот буфер, который возвращает asCharBuffer() (какой-то внутренний класс DirectByteBuffer), поддерживает только кодировку UTF-16. Скорость обработки файла при этом сопостовима со скоростью в варианте с CharsetDecoder (правда, там сам исходный файл в UTF-16 в два раза длиннее, так что вроде бы работает быстрее, но нам ведь нужно ехать, а не шашечки smile).

Поиски способа сменить дефолтную кодировку ни к чему не привели, так что, как говорится, не выеживайтесь, Иван Иваныч, слушайте вашу любимую песню "Валенки" smile В смысле, юзайте CharsetDecoder и не дрыгайтесь.

На случай, если у кого-то возникнет аналогичная задача, привожу код манипуляций:

Код


    File file = new File("your-file-location");

    RandomAccessFile raf = new RandomAccessFile(file, "r"); // r, wr, p, etc.
    FileChannel fc = raf.getChannel();

    // Get the file's size and then map it into memory
    MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, size);

    // Setup the decoder
    Charset charset = Charset.forName("ISO-8859-1");
    CharsetDecoder decoder = charset.newDecoder();
    CharBuffer buffer = decoder.decode(bb);

    // Делаем что хотим с buffer, например:
    Pattern p = new Pattern("\\n");
    Matcher m = p.matcher(buffer);

    if (m.find())
    {
        System.out.println("LF found");
    }

    raf.close();



Это сообщение отредактировал(а) Stampede - 30.4.2005, 17:22


--------------------
"If you want something done right, do it yourself"
По секрету: выучить английский - реально!
PM WWW   Вверх
Zandr
Дата 4.5.2005, 07:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 433
Регистрация: 16.7.2004
Где: Новосибирск

Репутация: 9
Всего: 13



Вот не совсем понятное место:
Цитата
CharBuffer buffer = decoder.decode(bb);

Не прошарил как работает этот метод... Он не пытается сразу весь файл перекачать в память? Или как задумано дает char'ы что называется on demand?
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0785 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.