Чтение файлов блоками

Обсуждение программ nnCron и nnCron LITE

Чтение файлов блоками

Postby mihast » Fri, 07 Aug 2015, 10:58

Для чтения логов удобно использовать read-by-line.spf Цикл READ-BY-LINE: ;READ-BY-LINE замечательно обрабатывает текстовые файлы.

Но как быть, когда лог большой, а в конец его добавилось несколько строк. Их тоже надо обработать.

Вопрос: Как инициализировать чтение READ-BY-LINE: не с первой позиции, а с произвольной или хотя бы с первой не обработанной ?
mihast
 
Posts: 51
Joined: Tue, 23 Aug 2005, 21:14

Re: Чтение файлов блоками

Postby VoidVolker » Fri, 07 Aug 2015, 11:06

Такой возможности не предусмотрено.
95% вопросов уже обсуждались на форуме или ответы на них есть в мануале.        nnCron 1.93 b15.exe
Как правильно задавать вопросы.
User avatar
VoidVolker
Site Admin
 
Posts: 2898
Joined: Tue, 25 Apr 2006, 17:56

Re: Чтение файлов блоками

Postby mihast » Fri, 07 Aug 2015, 11:39

Есть такое слово REPOSITION-FILE. Как и для чего оно используется ? Может можно с его помощью как-то выкрутиться ?
mihast
 
Posts: 51
Joined: Tue, 23 Aug 2005, 21:14

Re: Чтение файлов блоками

Postby VoidVolker » Fri, 07 Aug 2015, 12:42

viewtopic.php?f=5&t=13237
Code: Select all
S" path\to\file" FOR-FILE-LINES
    LINE-NUMBER 100 > IF
        <код>
    THEN
;FOR-FILE-LINES

Проходить по содержимому всего файла надо в любом случае. Если надо отсчитать определенное число строк с конца файла:
Code: Select all
S" path\to\file" FILE 2DUP 0 -ROT
FOR-LINES
    DROP LINE-NUMBER
;FOR-LINES
-ROT
FOR-LINES
    LINE-NUMBER OVER 5 - > IF
        <код>
    THEN
;FOR-LINES
DROP

А еще можно файл в список закинуть и работать уже со списком (плагин Lists.spf):
Code: Select all
STRING-LIST: myFile
S" path\to\file" FOR-FILE-LINES
    FOUND-LINE myFile!
;FOR-FILE-LINES
myFile# 6 - myFile#@ TYPE CR \ Получение строки 5 с конца файла (нумерация элементов в списке начинается с 0, поэтому myFile# 1- myFile#@ и есть последний элемент)
myFile LIST-FREE
95% вопросов уже обсуждались на форуме или ответы на них есть в мануале.        nnCron 1.93 b15.exe
Как правильно задавать вопросы.
User avatar
VoidVolker
Site Admin
 
Posts: 2898
Joined: Tue, 25 Apr 2006, 17:56

Re: Чтение файлов блоками

Postby VoidVolker » Fri, 07 Aug 2015, 14:27

Какова задача в целом?
95% вопросов уже обсуждались на форуме или ответы на них есть в мануале.        nnCron 1.93 b15.exe
Как правильно задавать вопросы.
User avatar
VoidVolker
Site Admin
 
Posts: 2898
Joined: Tue, 25 Apr 2006, 17:56

Re: Чтение файлов блоками

Postby ANR Daemon » Sun, 09 Aug 2015, 19:46

VoidVolker wrote:Какова задача в целом?

Присоединяюсь к вопросу.
Поставьте задачу внятно, будет внятное решение.
ANR Daemon
 
Posts: 234
Joined: Mon, 26 Feb 2007, 22:59

Re: Чтение файлов блоками

Postby mihast » Sat, 15 Aug 2015, 16:05

Поправил первую версию read-by-line. Но что-то где-то не доделал (недопонял) и теперь при возврате через RBL-EXIT на стэке что-то лишнее :(
Помогите исправить...

Code: Select all
USER-VALUE LINE-NUMBER

MODULE: READ-BY-LINE-MODULE
   \ Autor:  VoidVolker (VoidVolker@gmail.com)
   \ Date:   21:56 20/01/09
      USER-VALUE fEND
      USER-VALUE Lc
      USER-VALUE fPos

      : (READ-BY-LINE) { xt \ Lf -- }  ( a u xt -- )
         fEND >R  Lc >R  fPos >R LINE-NUMBER >R \ Сохраняем переменные (для вложенных случаев)
         -1 TO fEND
         1 TO LINE-NUMBER
         40002   \ максимальная длина строки (в символах) + 2
         ALLOCATE THROW TO Lc
         R/O OPEN-FILE-SHARED THROW TO Lf
         fPos IF fPos S>D Lf REPOSITION-FILE THROW THEN
         BEGIN
            Lc 40000 Lf READ-LINE THROW
            Lf FILE-POSITION THROW D>S TO fPos
            fEND AND WHILE  \ Выход по команде   
            Lc + 0 SWAP C!
            xt EXECUTE
            LINE-NUMBER 1+ TO LINE-NUMBER
         REPEAT  DROP
         Lf CLOSE-FILE DROP
         Lc FREE DROP
         R> LINE-NUMBER R> fPos R> TO Lc  R> TO fEND  \ Восстанавливаем переменные
      ;

   EXPORT

       : ?RBL-EXIT   \ ( ? -- ) \ Условный выход из цикла
          NOT TO fEND
       ;

       : RBL-EXIT   \ ( -- ) \ Выйти из цикла
          0 TO fEND
       ;
     
       : FOUND-LINE   \ ( -- a u ) \ Найденная строка
          Lc ASCIIZ>
       ;

       : FOUND-LINE_Z  \ ( -- a ) \ Найденная строка Z
          Lc
       ;
       
       : RBL-GetPos \ ( -- n )  \ Позиция в файле
         fPos
       ;
       
       : RBL-SetPos \ ( n -- )  \ Установить начальную позицию
         TO fPos
       ;
       
       : RBL-Reset \ ( -- )  \ Читать с начала файла
         0 TO fPos
       ;

       : READ-BY-LINE \ compile: ( -- )
                   \  execute: ( a u --)
           POSTPONE [NONAME
       ; IMMEDIATE

       : ;READ-BY-LINE
           POSTPONE NONAME]
           POSTPONE (READ-BY-LINE)
       ; IMMEDIATE

       : READ-BY-LINE: eval-string,  POSTPONE READ-BY-LINE ; IMMEDIATE

   ;MODULE

\EOF

READ-BY-LINE: "filename"
         < .... > \ Ваши требуемые действия со строкой из файла
;READ-BY-LINE
Внутри цикла можно использовать следующие слова:
FOUND-LINE \ ( -- a u ) \ Найденная строка.
RBL-EXIT \ ( -- ) \ Выйти из цикла. Выход будет произведен в начале следующей итерации.
?RBL-EXIT \ ( ? -- ) \ Условный выход из цикла
mihast
 
Posts: 51
Joined: Tue, 23 Aug 2005, 21:14

Re: Чтение файлов блоками

Postby VoidVolker » Sat, 15 Aug 2015, 16:17

Зачем выключать BBCode и использовать его? Чего именно поправил? С какой целью? Если вот этого функционала мало, могу еще добавить. Как уже говорил, если надо сразу взять из файла какой-то кусок, то для этого есть OPEN-FILE -> READ-FILE. Какова задача-то?
95% вопросов уже обсуждались на форуме или ответы на них есть в мануале.        nnCron 1.93 b15.exe
Как правильно задавать вопросы.
User avatar
VoidVolker
Site Admin
 
Posts: 2898
Joined: Tue, 25 Apr 2006, 17:56

Re: Чтение файлов блоками

Postby mihast » Sat, 15 Aug 2015, 16:27

VoidVolker wrote:Какова задача в целом?


Динамическое чтение больших лог файлов (более 500 мб за день)
mihast
 
Posts: 51
Joined: Tue, 23 Aug 2005, 21:14

Re: Чтение файлов блоками

Postby mihast » Sat, 15 Aug 2015, 16:37

VoidVolker wrote:Чего именно поправил? С какой целью? Какова задача-то?


У меня задача - слежение за БОЛЬШИМИ по размеру лог-файлами. Сейчас с теми добавками, что сделаны постом выше - это достигнуто

Code: Select all
fVAR ТекущаяПозиция

ТекущаяПозиция S>NUM RBL-SetPos

READ-BY-LINE: "filename"
  RBL-GetPos N>S TO ТекущаяПозиция
         < .... > \ Анализ и требуемые действия со строкой из файла
;READ-BY-LINE


Но, если я покидаю цикл через RBL-EXIT на стеке остается мусор.
mihast
 
Posts: 51
Joined: Tue, 23 Aug 2005, 21:14

Re: Чтение файлов блоками

Postby VoidVolker » Sat, 15 Aug 2015, 17:37

Эмм... READ-BY-LINE - это как бы не тот инструмент/механизм, который нужен для чтения из любого места в файле. Это построчное чтение и построчная обработка. Новая версия позволяет обрабатывать любые строки. Если надо прочитать произвольное место в файле, то это делается следующим образом:
Code: Select all
CREATE fbuf 256 ALLOT
: ftest { \ h -- }
    S" C:\file.txt"
    R/O                             \ a u fam    \ Указываем режим работы с файлом
    OPEN-FILE-SHARED THROW          \ ior|h      \ Открываем файл - на стеке хэндл
    TO h                                       \ Сохраняем хэндл открытого файла
   
    h FILE-SIZE THROW               \ ud1        \ Получаем размер файла - это число двойной длины
   
    8 S>D                           \ ud1 ud2    \ Нам надо последние 8 байт файла (например) - конвертируем число в число двойоной длины (по факту два числа, старшие разряды - ноль)
    D-                              \ ud3        \ Вычисляем смещение от конца (например)
    h REPOSITION-FILE THROW                    \ Изменяем указатель текщуей позици в файле на ud3
   
    fbuf 8                          \ addr u     \ Кладем на стек адрес (буфер) для файла и сколько надо байт прочитать
    h READ-FILE THROW               \ u          \ На стеке остается число прочитанных байт
   
    h CLOSE-FILE THROW              \ u          \ Закрываем файл
   
    fbuf SWAP DUMP                  \ Выводим в консоль дамп
;

Т.о., если мы хотим прочитать произвольный кусок файла, то нам следует написать следующее слово:
Code: Select all
: D>0  \ ( ud -- ? )
    0 0 D>
;

: FILE-BLOCK   { offset size \ h buf -- }  \ ( a0 u0 offset size -- a1 u1 )
    R/O OPEN-FILE-SHARED THROW TO h
    h FILE-SIZE THROW                   \ ud
    2DUP                                \ ud ud
    offset size + S>D D> IF             \ ud        \ Проверяем размер файла и смещение - иначе выходим
        offset 0< IF                        \ ud    \ Если смещение отрицательное - то отсчитываем с конца файла
            offset S>D D+                   \ ud1   \ Прибавляем отрицательное смещение к длине файла - получаем смещение от конца файла
        ELSE
            2DROP offset S>D                \ ud2   \ Выкидываем размер файла - он больше не нужен, вместо него используем смещение как смещение от начала файла
        THEN
        h REPOSITION-FILE THROW                     \ Смещаем позицию в файле
        size CELL+ ALLOCATE THROW TO buf            \ Выделяем память для чтения блока файла
        buf size h
        READ-FILE THROW          \ u1    \ Читаем нужный блок. На стеке - размер прочитанного блока из файла
        buf SWAP                            \ a1 u1
    ELSE
        2DROP
        S" "
    THEN
    h CLOSE-FILE THROW
;

И для построчной обработки последних строк файла делаем так:
Code: Select all
S" C:\file.txt" -10240 10240 FILE-BLOCK FOR-LINES
    LINE-NUMBER 1 = IF EXIT THEN    \ Игнорируем первую строку - т.к. она почти всегда будет обрезанной (Да-да, текущую итерацию можно закончить через обычный [b]EXIT[/b] т.к. данный блок кода является безымянным словом.)
   \ Обрабатываем Все остальные строки

;FOR-LINES
95% вопросов уже обсуждались на форуме или ответы на них есть в мануале.        nnCron 1.93 b15.exe
Как правильно задавать вопросы.
User avatar
VoidVolker
Site Admin
 
Posts: 2898
Joined: Tue, 25 Apr 2006, 17:56

Re: Чтение файлов блоками

Postby mihast » Sat, 15 Aug 2015, 19:02

Как бы ДА. Все что Вы написали - это правильно.

Но, наверное, Вы не так себе представляете обработку лог файлов, как я ее произвожу. Я каждую минуту запускаю слово, которое читает через READ-BY-LINE: лог файл и обрабатываю все, что там есть. Попутно запоминаю последнюю считанную в файле позицию. Еще раз - я разбираю лог-файл ПОЛНОСТЬЮ, с первой до последней строчки. Именно по-этому - READ-BY-LINE:
Но лог - не архивный, а "живой" и через минуту у меня в конец опять добавилось от сотен до 5000 строк. Таймер опять вызывает задачу по чтению и я обрабатываю "хвост". Через READ-BY-LINE:

Все сейчас именно так и работает, как я описал. За исключением выхода из цикла по RBL-EXIT. Он почему-то оставляет мусор на стэке. Подскажите, пожалуйста, что в моей версии не так ? Вроде бы я внес минимум исправлений....
mihast
 
Posts: 51
Joined: Tue, 23 Aug 2005, 21:14

Re: Чтение файлов блоками

Postby VoidVolker » Sat, 15 Aug 2015, 19:52

Ага, обработать построчно, запомнить размер файла и использовать этот размер в следующей итерации как смещение.
mihast wrote:За исключением выхода из цикла по RBL-EXIT. Он почему-то оставляет мусор на стэке. Подскажите, пожалуйста, что в моей версии не так ? Вроде бы я внес минимум исправлений....

Code: Select all
R> LINE-NUMBER R> fPos   \ old_n new_n old_fPos new_fpos

Code: Select all
R> TO LINE-NUMBER R> TO fPos
95% вопросов уже обсуждались на форуме или ответы на них есть в мануале.        nnCron 1.93 b15.exe
Как правильно задавать вопросы.
User avatar
VoidVolker
Site Admin
 
Posts: 2898
Joined: Tue, 25 Apr 2006, 17:56

Re: Чтение файлов блоками

Postby mihast » Sun, 16 Aug 2015, 07:07

Спасибо !

Может тогда еще подскажете, как определить USER-VALUE двойной длины ?
mihast
 
Posts: 51
Joined: Tue, 23 Aug 2005, 21:14

Re: Чтение файлов блоками

Postby VoidVolker » Sun, 16 Aug 2015, 10:55

Ап! Теперь, конец лога можно обрабатывать так:
Code: Select all
fVAR CurrentPos
S" C:\file.txt" CurrentPos S>NUM FILE-REST FOR-LINES

;FOR-LINES
S" C:\file.txt" FSIZE DOUBLE>S TO CurrentPos

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

Если надо именно VALUE - то это надо взять исходник USER-VALUE и изменить его на работу с переменными двойной длины. А если надо просто двойную ячейку в памяти, то можно сделать так:
Code: Select all
USER-CREATE UserDVar 2 CELLS USER-ALLOT

И работать как с обычной двойной переменной.
95% вопросов уже обсуждались на форуме или ответы на них есть в мануале.        nnCron 1.93 b15.exe
Как правильно задавать вопросы.
User avatar
VoidVolker
Site Admin
 
Posts: 2898
Joined: Tue, 25 Apr 2006, 17:56

Next

Return to nnCron forum (Russian)

Who is online

Users browsing this forum: Google [Bot] and 2 guests