Что нового

Скрипт не успевает прочесть строку в логфайле

A

at

Гость
Версия AutoIt: 3.3.6.1

Описание: Час Добрый, Всем! Скрипт должен выполнять команду при появлении в файле prog.log определенной строки. Все, что я пробовал сделать не приносит положительный результат. В процессе решения этого вопроса, у меня сложилось мнение, что скрипт просто не успевает прочесть строку. Почему я так считаю: если взять мой скрипт или вариант, который предложил madmasles и протестировать на копии этого логфайла условие появления новой строки все работает правильно. Но стоит только подключить скрипт к реальному логу и ситуация меняется – скрипт просто не реагирует на появление заданной строки. Запрета на чтение логфайла нет, проверил. Прошу помочь решить данную задачу.


Мой скрипт:
Код:
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

$hForm = GUICreate('PROGA', 152, 65, 225, 150)
$vInput_1 = GUICtrlCreateInput('', 32, 8, 105, 21)
$vLabel_Info = GUICtrlCreateLabel(' ... жду сигнал', 32, 40, 84, 17)
$vCheckbox1 = GUICtrlCreateCheckbox('', 8, 9, 17, 15)
GUISetState(@SW_SHOW)

Global $vScript_Name, $sFile, $sRead

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        EndSwitch
         If GUICtrlRead($vCheckbox1) = $GUI_CHECKED Then
             $vScript_Name = GUICtrlRead($vInput_1)
         EndIf
        
            $sFile = 'C:\prog.log'
            $sRead = FileReadLine($sFile, -1)
            $sString_Buy = StringRegExp($sRead, '(?m)^(.*?\[.*?INFO.*?Script:\(Script:' & $vScript_Name & '\).*?На старт.*?БОЛИД.*)$')
            $sString_Sale = StringRegExp($sRead, '(?m)^(.*?\[.*?INFO.*?Script:\(Script:' & $vScript_Name & '\).*?На старт.*?ФЕРАРРИ.*)$')

         If $sString_Buy Then
             Buy()

         ElseIf $sString_Sale Then
             Sale()
             
         EndIf
WEnd

Func Buy()
        Sleep(10)
$vLabel_Info = GUICtrlCreateLabel("БОЛИД", 32, 40, 84, 17)
EndFunc

Func Sale()
        Sleep(10)
$vLabel_Info = GUICtrlCreateLabel("ФЕРАРРИ", 32, 40, 84, 17)
EndFunc

CreatoR : В названии темы заложен вопрос «Как прочитать последнюю строку в файле», ответ на него получен (в самом же вопросе по всей видимости).
Видимо вопрос поставлен неправильно.
Я изменил название темы и постарался более конкретнее объяснить задание.
 

sngr

AutoIT Гуру
Сообщения
1,010
Репутация
408
Re: [Данные, строки] Чтение последней строки в текстовом файле

покажите prog.log
 

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Re: [Данные, строки] Чтение последней строки в текстовом файле

Код:
#include <File.au3>

$sPath = @ScriptDir & '\prog.log'
$hFile = FileOpen($sPath)
$Count = _FileCountLines($sPath)

For $i = $Count To 1 Step -1
	$sRead = FileReadLine($hFile, $Count)
	If $sRead <> '' Then
        MsgBox(0, 0, $sRead)
		ExitLoop
	EndIf
Next

FileClose($hFile)
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Re: [Данные, строки] Чтение последней строки в текстовом файле

Справку когда читать начнём:

Код:
$sPath = @ScriptDir & '\prog.log'
$sRead = FileReadLine($sPath, -1)
MsgBox(0, 0, $sRead)
 
Автор
A

at

Гость
Re: [Данные, строки] Чтение последней строки в текстовом файле

Viktor1703, спасибо за вариант, завтра попробую в рабочем режиме. Хотелось бы всеже понять, где ошибка в моем скрипте.

CreatoR,
Справку когда читать начнём:
Код:
$sPath = @ScriptDir & '\prog.log'
$sRead = FileReadLine($sPath, -1)
MsgBox(0, 0, $sRead)
Разве в моем скрипте не так ?


Добавлено:
Сообщение автоматически объединено:

Не знаю почему, но в рабочем режиме, когда появляетя нужная строка в файле prog.log, мой скрипт не реагирует на это событие.
 

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Re: [Данные, строки] Чтение последней строки в текстовом файле

А какое значение скрипт ищет в файле? и как он его найдёт, если в файле последняя строка:

Код:
12:40:05.59[13]DEBUG:

А лучше объясните, как должен работать скрипт и что искать...
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Re: [Данные, строки] Чтение последней строки в текстовом файле

at [?]
Разве в моем скрипте не так ?
Это я про скрипт Viktor1703, но в любом случае, информации мало.

В названии темы заложен вопрос «Как прочитать последнюю строку в файле», ответ на него получен (в самом же вопросе по всей видимости).
Видимо вопрос поставлен неправильно.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Re: [Данные, строки] Чтение последней строки в текстовом файле

at,
Если я Вас правильно понял, то попробуйте так.
Код:
#include <GUIConstantsEx.au3>

Global $fBuy, $fSale, $fNo

$hForm = GUICreate('PROGA', 152, 65)
$nInput = GUICtrlCreateInput('PC', 32, 8, 105, 21)
$nLabel_Info = GUICtrlCreateLabel('... жду сигнал', 32, 40, 84, 17)
$nCheckbox = GUICtrlCreateCheckbox('', 8, 9, 17, 15)
GUISetState()

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
		Case $nCheckbox
			If BitAND(GUICtrlRead($nCheckbox), $GUI_CHECKED) Then
				$fNo = True
				_CheckLog()
				AdlibRegister('_CheckLog');250 ms
			Else
				AdlibUnRegister('_CheckLog')
				GUICtrlSetData($nLabel_Info, '... жду сигнал')
				$fBuy = False
				$fSale = False
			EndIf
	EndSwitch
WEnd

Func _CheckLog()
	Local $s_File = @ScriptDir & '\prog.log', $s_Script_Name, $s_Read

	$s_Script_Name = GUICtrlRead($nInput)
	If Not $s_Script_Name Then
		GUICtrlSetData($nLabel_Info, 'Error Script_Name')
		Return
	EndIf
	$s_Read = FileReadLine($s_File, -1)
	If Not $s_Read Then
		GUICtrlSetData($nLabel_Info, 'Error Read')
		Return
	EndIf
	If StringRegExp($s_Read, '^(.*?\[.*?INFO.*?Script:\(Script:' & $s_Script_Name & '\).*?На старт.*?БОЛИД.*)$') Then
		$fSale = False
		$fNo = True
		If Not $fBuy Then
			Beep(300, 50)
			Buy()
			$fBuy = True
		EndIf
		Return
	EndIf
	If StringRegExp($s_Read, '^(.*?\[.*?INFO.*?Script:\(Script:' & $s_Script_Name & '\).*?На старт.*?ФЕРАРРИ.*)$') Then
		$fBuy = False
		$fNo = True
		If Not $fSale Then
			Beep(300, 50)
			Sale()
			$fSale = True
		EndIf
		Return
	EndIf
	If $fNo Then
		Beep(100, 50)
		GUICtrlSetData($nLabel_Info, 'Пока нет')
		$fNo = False
	EndIf
	$fBuy = False
	$fSale = False
EndFunc   ;==>_CheckLog

Func Buy()
	GUICtrlSetData($nLabel_Info, 'БОЛИД')
EndFunc   ;==>Buy

Func Sale()
	GUICtrlSetData($nLabel_Info, 'ФЕРАРРИ')
EndFunc   ;==>Sale
 
Автор
A

at

Гость
madmasles, благодарю за помощь, но вариант предложенный Вами пропускает появление новой строки в логфайле. Я изменил название темы и поправил свой вопрос в шапке.
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
imho, всё потому что GUIGetMsg.
Но поскольку тема называется не "почему я не люблю GUI", то я просто предложу альтернативный вариант.

Код:
$sFile = 'C:\prog.log'
$line_number = 1

While 1
            $sRead = FileReadLine($sFile, $line_number)

            While @error <> 0
                        Sleep(1000)
                        $sRead = FileReadLine($sFile, $line_number)
            WEnd 

            $line_number += 1

            $sString_Buy = StringRegExp($sRead, '(?m)^(.*?\[.*?INFO.*?Script:\(Script:' & $vScript_Name & '\).*?На старт.*?БОЛИД.*)$')
            $sString_Sale = StringRegExp($sRead, '(?m)^(.*?\[.*?INFO.*?Script:\(Script:' & $vScript_Name & '\).*?На старт.*?ФЕРАРРИ.*)$')

         If $sString_Buy Then
             Buy()

         ElseIf $sString_Sale Then
             Sale()
             
         EndIf
WEnd
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Я не вникал в суть дела, но скрипт не обязан переодически читать файл со скоростью Ferrari. Алгоритм должен быть такой:

  • Считывается весь файл.
  • Ищется то, что нужно и запоминается номер последней строки в файле.
  • При следующей проверке опять считывается весь файл, но поиск производится, начиная с ранее запомненного номера строки.
  • Опять запоминается номер последней строки.
  • и т.д.

Только в этом случае можно гарантировать, что искомая строка не будет пропущена.



Добавлено:
Сообщение автоматически объединено:

at сказал(а):
C2H5OH спасибо за вариант, завтра на работе попробую. Если можно подробнее об этом:
imho, всё потому что GUIGetMsg.

GUIGetMsg() здесь вообще ни при чем.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
at,
Как часто вносятся данные в лог и что за программа их вводит?
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Я написал imho - то есть это моё субъективное мнение.
Потому что я не знаю как работает GUIGetMsg, но его игры с быстродействием процессора мне не нравятся.

По сути проблемы:
Насколько я понимаю, в промежуток между чтениями ПОСЛЕДНЕЙ строки происходит появление нескольких новых строк. (мне кажется что madmasles сделал такое же предположение)
То есть читая в цикле не все строки подряд, а только последнюю через какой-то промежуток времени, мы обязательно будем пропускать строки.
Что может вызывать задержки? Только GUIGetMsg и StringRegExp.

Ещё и запись строки в файл вовсе не является событием, которое фиксирует GUIGetMsg...
Поэтому я и предложил вариант тупого чтения всех строк подряд.
(сам понимаю что вариант не очень - FileReadLine при каждом обращении будет читать все строки с начала файла. А что делать? :whistle:smile:
 
Автор
A

at

Гость
Yashied благодарю за подсказку. Если можно ссылку на пример, в справках я не нашел ничего подобного.

C2H5OH, я пробовал читать все строки подряд, это возможно. Но это не то, что нужно.

...что за программа их вводит?
madmasles, прошу Сообщество простить меня, название программы скинул в личку.
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Ну а это по вашему что делает?

Код:
$sFile = 'C:\prog.log'
$line_number = 1

While 1
            $sRead = FileReadLine($sFile, $line_number)

            While @error <> 0
                        Sleep(1000)
                        $sRead = FileReadLine($sFile, $line_number)
            WEnd

            $line_number += 1
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
at
смотри в сторону FileRead
Код:
$sFile = 'C:\prog.log'
While 1
    $sRead = FileRead($sFile)
    ; В $sRead находится все содержимое файла на момент открытия
    ; При всех последующих чтениях в переменной будет только то содержимое, которое появилось с момента последнего чтения
    Sleep(1000)
WEnd



Добавлено:
Сообщение автоматически объединено:

C2H5OH
так делать не стоит, т.к. FileReadLine будет считывать файл с самого начала снова и снова. FileRead ставит указатель на момент последнего чтения.
 
Автор
A

at

Гость
Kaster, спасибо за помощь. По Вашему совету, срабатывает многократное повторение условия, на одну и ту же строку. Я пытаюсь сделать так, чтобы условие отрабатывалось один только раз для каждой новой строчки логфайла.
Делал так:
Код:
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

$hForm = GUICreate('PROGA', 152, 65, 225, 150)
$vInput_1 = GUICtrlCreateInput('', 32, 8, 105, 21)
$vLabel_Info = GUICtrlCreateLabel(' ... жду сигнал', 32, 40, 84, 17)
$vCheckbox1 = GUICtrlCreateCheckbox('', 8, 9, 17, 15)
GUISetState(@SW_SHOW)

Global $vScript_Name, $sFile, $sRead

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
		EndSwitch
		 If GUICtrlRead($vCheckbox1) = $GUI_CHECKED Then
			$vScript_Name = GUICtrlRead($vInput_1)
		 EndIf
		
            $sFile = 'C:\prog.log'
			$sRead = FileRead($sFile)
			Sleep(1000)
			$sString_Buy = StringRegExp($sRead, '(?m)^(.*?\[.*?INFO.*?Script:\(Script:' & $vScript_Name & '\).*?На старт.*?БОЛИД.*)$')
			$sString_Sale = StringRegExp($sRead, '(?m)^(.*?\[.*?INFO.*?Script:\(Script:' & $vScript_Name & '\).*?На старт.*?ФЕРАРРИ.*)$')

		 If $sString_Buy Then
			 Buy()

		 ElseIf $sString_Sale Then
			 Sale()
			 
		 EndIf
WEnd

Func Buy()
		Sleep(10)
$vLabel_Info = GUICtrlCreateLabel("БОЛИД", 32, 40, 84, 17)
EndFunc

Func Sale()
		Sleep(10)
$vLabel_Info = GUICtrlCreateLabel("ФЕРАРРИ", 32, 40, 84, 17)
EndFunc
Хороший вариант предложил Yashied, подскажите, пожалуйста, как это сделать.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
at сказал(а):
Хороший вариант предложил Yashied, подскажите, пожалуйста, как это сделать.

Это очень просто.

Код:
$Buff = ''
While 1
	$Data = FileRead('prog.log')
	If Not @error Then
		$Text = StringTrimLeft($Data, StringLen($Buff))
		$Buff = $Data
		If $Text Then
			; Поиск чего-то в переменной $Text...
		EndIf
	EndIf
	Sleep(1000)
WEnd


Поиск лучше производить с помощью рег. выражений, но здесь, к сожалению, я не помощник.
 
Верх