Задача: просмотр текстового файла
Модератор: Модераторы
Задача: просмотр текстового файла
Есть задача организовать просмотр некого текстового файла. Компонент memo не подходит, т.к. он предварительно загружает весь файл целиком в память (что не приемлимо для файлов ОЧЕНЬ большого размера).
В принципе нечто написал,выводом текста на канву,одна проблема: если организовать "листание" страниц вперед у меня не вызывает проблем, то с листанием "назад" беда. Не могу придумать умный алгоритм поиска предыдущей строки (нужно понимать что "строка" может быть любой длинны и перенос на экране строчки не означает то-же самое в файле). Все алгоритмы которые я придумываю или слишком сложны или могут теоретически вызывать сбивание абзацев.
В принципе нечто написал,выводом текста на канву,одна проблема: если организовать "листание" страниц вперед у меня не вызывает проблем, то с листанием "назад" беда. Не могу придумать умный алгоритм поиска предыдущей строки (нужно понимать что "строка" может быть любой длинны и перенос на экране строчки не означает то-же самое в файле). Все алгоритмы которые я придумываю или слишком сложны или могут теоретически вызывать сбивание абзацев.
- alexs
- долгожитель
- Сообщения: 4066
- Зарегистрирован: 15.05.2005 23:17:07
- Откуда: г.Ставрополь
- Контактная информация:
А тупой поиск символов CRLF чем не устраивает?
Только сразу оговориться - напрямую в файле - это дохлый номер.
А вот если будешь работать с буфером упреждающего чтения - то результат будет приемлем.
PS
У меня была подобная задача - сеансово искать последовательности определённых симовлов в файлах размерами несколько сот гиг. Причём туда постоянно дописывались данные.
Я сохранял позицию последнего обращения в конфиге между сеансами. А в следующем сеансе читал в буфер с сохраннённой позиции, выделял в нём строки и делал поиск уже в них.
Работает шустро...
Только сразу оговориться - напрямую в файле - это дохлый номер.
А вот если будешь работать с буфером упреждающего чтения - то результат будет приемлем.
PS
У меня была подобная задача - сеансово искать последовательности определённых симовлов в файлах размерами несколько сот гиг. Причём туда постоянно дописывались данные.
Я сохранял позицию последнего обращения в конфиге между сеансами. А в следующем сеансе читал в буфер с сохраннённой позиции, выделял в нём строки и делал поиск уже в них.
Работает шустро...
Так устраивает. Но яж говорю, строка в файле не обязательно обозначает строку на экране. Ширина экрана же может быть меньше длинны строки. Соответственно будут "виртуальные переносы" строки... Т.е. например: допустим строка в файле: 123456789. Допустим ширина экрана 4 символа. Допустим позиция текущая курсора - на 9. "Листаем назад", получаем:
т.е. получив "1", обнаруживаем что строка кончилась. Абзац как итог сбит. Если хотим чтобы было выравнивание "с лева", тогда таки придется заморачиваться с упреждающим чтением, предварительной разбивкой на строки экрана и т.п. усложненная муть
Добавлено спустя 3 минуты 14 секунд:
Придется таки все-же видимо "набирать в памяти" сначала строку экрана, а потом уже выводить её на экран.
Код: Выделить всё
1
2345
6789
т.е. получив "1", обнаруживаем что строка кончилась. Абзац как итог сбит. Если хотим чтобы было выравнивание "с лева", тогда таки придется заморачиваться с упреждающим чтением, предварительной разбивкой на строки экрана и т.п. усложненная муть
Добавлено спустя 3 минуты 14 секунд:
Придется таки все-же видимо "набирать в памяти" сначала строку экрана, а потом уже выводить её на экран.
Все хорошо на ПК. Но попробовал с "упреждающей" обработкой файла на WindowsCE - файлик 1 мб, грузился для просмотра 2 минуты
Думаю...
Думаю...
- Brainenjii
- энтузиаст
- Сообщения: 1351
- Зарегистрирован: 10.05.2007 00:04:46
Если файлик формируется на большом брате, то можно его сначала нашинковать на желаемые кусочки
А если по мере просмотра файла "индексировать" его. Т.е. запоминать сдвиг от начала файла до строки, с учетом переносов. Прокрутка назад все равно будет тяжелой (сначала на начало файла потом на нужную стоку), но не надо будет весь файл сначала просматривать. Потом, для уменьшения количества обращений к диску, можно сделать буфер и показывать в том же Memo только окно этого буфера. При приближении к началу или концу буфера считывать некое количество строк.
- alexs
- долгожитель
- Сообщения: 4066
- Зарегистрирован: 15.05.2005 23:17:07
- Откуда: г.Ставрополь
- Контактная информация:
donpadlo
А почему так долго?
Смысл задачи - только найти начала строк. А потом создать масив строк и скопировать содержимое из буфера по индексам начала в массив.
Тут же нет таких тяжёлых вычислений. И файловые операции сведены к минимуму.
vada
При реально больших файлах сам полный индекс для файла будет очень большим.
Хотя - для файлов порядка 10-100 метров - смысл имеет.
Но у этого варианта недостаток - если надо сразу посмотреть строки конца файла - это будет тормозить. Фактически в этом случаее надо перечитать весь файл.
А почему так долго?
Смысл задачи - только найти начала строк. А потом создать масив строк и скопировать содержимое из буфера по индексам начала в массив.
Тут же нет таких тяжёлых вычислений. И файловые операции сведены к минимуму.
vada
При реально больших файлах сам полный индекс для файла будет очень большим.
Хотя - для файлов порядка 10-100 метров - смысл имеет.
Но у этого варианта недостаток - если надо сразу посмотреть строки конца файла - это будет тормозить. Фактически в этом случаее надо перечитать весь файл.
Вишь в чем дело, нужнож еще высчитывать длинну строки. В каждой строчке может быть разное количество символов из-за разной ширины букв.. Потому и тяжелый процесс на самом деле получается
- Brainenjii
- энтузиаст
- Сообщения: 1351
- Зарегистрирован: 10.05.2007 00:04:46
Кстати, если сделать вот так
то и расчитывать длину строки, возможно, не нужно
Код: Выделить всё
Procedure TForm1.FormPaint(Sender: TObject);
Var
aRect: TRect;
aStyle: TTextStyle;
Begin
aRect.Top := 0;
aRect.Left := 10;
aRect.Bottom := 100;
aRect.Right := 110;
aStyle.SingleLine := FALSE;
aStyle.Opaque := FALSE;
Canvas.TextRect(aRect, 10, 10, 'Привет, прекрасный безумный мир о котором я ' +
'так мало знаю сейчас', aStyle);
End;
то и расчитывать длину строки, возможно, не нужно
не не вариант, придется контролировать выход за границы экрана.. Строкаж из файла может быть длиннее заполнения квадрата экрана
- alexs
- долгожитель
- Сообщения: 4066
- Зарегистрирован: 15.05.2005 23:17:07
- Откуда: г.Ставрополь
- Контактная информация:
donpadlo
1. Отображай моноширинным шрифтом - очень способствует
2. Расчёт свёртки делай 1 раз - после формирования массива строки или после изменения размеров области отображения. Значения кэшируй - например пусть у тебя строится доп массив строк с фактическими значениями для отображения.
Но это уже не будет относится к задаче определения строк в файле.
1. Отображай моноширинным шрифтом - очень способствует
2. Расчёт свёртки делай 1 раз - после формирования массива строки или после изменения размеров области отображения. Значения кэшируй - например пусть у тебя строится доп массив строк с фактическими значениями для отображения.
Но это уже не будет относится к задаче определения строк в файле.
vada
При реально больших файлах сам полный индекс для файла будет очень большим.
Хотя - для файлов порядка 10-100 метров - смысл имеет.
Мне трудно представить файл порядка 100 метров на WindowsCE. Нет, файл конечно может быть, но додуматься с ним там работать
Но у этого варианта недостаток - если надо сразу посмотреть строки конца файла - это будет тормозить. Фактически в этом случае надо перечитать весь файл.
Это не беда. Ориентировочный размер отображаемого кадра есть. Размер буфера тоже известен. И длинна файла не секрет. В чем проблема заполнить буфер окончанием файла, проиндексировать этот кусок, а потом кадр показать? Организовать этакий виртуальный прямой доступ к файлу.
Согласен, листать в таком случае назад будет напряжно, но это уже вопрос к файловой системе. На WindowsCE это будет, извиняюсь, жопа.
- alexs
- долгожитель
- Сообщения: 4066
- Зарегистрирован: 15.05.2005 23:17:07
- Откуда: г.Ставрополь
- Контактная информация:
vada писал(а): В чем проблема заполнить буфер окончанием файла, проиндексировать этот кусок, а потом кадр показать? Организовать этакий виртуальный прямой доступ к файлу.
Это мой вариант
Т.е на нижнем уровне работаешь с буферами фиксированного размера, а потом превращаешь их строки и индексируешь.
donpadlo
А почему проблема стала именно со строками?
Может изначально условия можно изменить. Ведь есть много хороших вариантов хранения данных
donpadlo писал(а):Так устраивает. Но яж говорю, строка в файле не обязательно обозначает строку на экране. Ширина экрана же может быть меньше длинны строки. Соответственно будут "виртуальные переносы" строки... Т.е. например: допустим строка в файле: 123456789. Допустим ширина экрана 4 символа. Допустим позиция текущая курсора - на 9. "Листаем назад", получаем:Код: Выделить всё
1
2345
6789
т.е. получив "1", обнаруживаем что строка кончилась. Абзац как итог сбит. Если хотим чтобы было выравнивание "с лева", тогда таки придется заморачиваться с упреждающим чтением, предварительной разбивкой на строки экрана и т.п. усложненная муть
Добавлено спустя 3 минуты 14 секунд:
Придется таки все-же видимо "набирать в памяти" сначала строку экрана, а потом уже выводить её на экран.
А как по дрругому? Приведенный Вами пример получается при посимвольном чтении файла. При построчном чтении вся строка уже будет в памяти и у Вас уже есть начало строки и, соответственно, начало абзаца. От него и надо плясать.
При испольльзовании посимвольного чтения жесткие тормоза будут именно из-за обращений к файлу.
Если посимвольное чтение является жестким условием, то, кроме текущей позиции в файле, храните текущую позицию на экране, тогда Ваш пример будет работать так:
Код: Выделить всё
Строка в файле: 123456789, ширина экрана 4 символа, позиция в файле - на 9, позиция на экране - 1. "Листаем назад", получаем:
1234
5678
9
