Что нового

[Данные, строки] Мониторинг логов большого размера (*.txt ~ 1,5 Mb)

kosjachok

Новичок
Сообщения
30
Репутация
3
Сделал такой монитор логов:
Код:
#include <Constants.au3>
#include <GUIConstantsEx.au3>
#include <GUIListBox.au3>
#include <WindowsConstants.au3>
#Include <File.au3>

;путь к любому текстовому логу
Local Const $sReceive = "C:\receive.log"

$Receive = FileOpen($sReceive, 0)
$hLinesR = _FileCountLines($sReceive)


$Form1 = GUICreate("Монитор логов", 640, 480, 100, 50, BitOR($WS_MAXIMIZEBOX,$WS_MINIMIZEBOX,$WS_SIZEBOX,$WS_THICKFRAME,$WS_SYSMENU,$WS_CAPTION,$WS_OVERLAPPEDWINDOW,$WS_TILEDWINDOW,$WS_POPUP,$WS_POPUPWINDOW,$WS_GROUP,$WS_TABSTOP,$WS_BORDER,$WS_CLIPSIBLINGS))
$ListR = GUICtrlCreateList("", 5, 30, 630, 450, BitXOR($LBS_NOSEL, $WS_VSCROLL,$WS_HSCROLL))
GUICtrlSetLimit(-1, 1300)
GUISetState(@SW_SHOW)

;доб существующих последних 10-ти строк лога в лист
$r = $hLinesR-10
While $r < $hLinesR
   $r = $r+1
   GUICtrlSetData ( $ListR, $r & '. '& FileReadLine ($Receive, $r) )
WEnd
_GUICtrlListBox_SetCaretIndex($ListR, $r)

AdlibRegister ( '_AddLine', 1000)

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch
WEnd

Func _AddLine()
   ;добавление новых строк в лист
			While $hLinesR < _FileCountLines($sReceive)
			   $hLinesR = $hLinesR + 1
			GUICtrlSetData ( $ListR, $hLinesR & '.-'& FileReadLine ( $Receive, $hLinesR) )
			_GUICtrlListBox_SetCaretIndex($ListR, $hLinesR)
			WEnd
EndFunc

Принцип работы - указываем лог (для примера можно взять лог любого ИМ), и в $ListR выводятся последние 10 строк + мониторятся новые строки, добавляющиеся в лог...
Вопрос: с маленькими логами работает нормально, с большими ~ 1,5 Mb, де > 20000 строк - $ListR очень медленно наполняется, и чем больше строк добавляется в лист - тем медленнее это происходит ... - Не поспевает за наполнением лога...
Как можно оптимизировать код для работы с большими логами?
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
kosjachok
ты каждый раз читаешь весь файл. понятное дело, что чем больше файл тем дольше будет происходить последующие пополнения.
Вообще, для больших файлов FileReadLine с указанием номера строки - моветон. Запоминай размер файла при последнем чтении, и при следующем чтении - делай FileSetPos и читай уже с этого момента. Тем же FileReadLine.
 
Автор
K

kosjachok

Новичок
Сообщения
30
Репутация
3
Kaster
Как то так:?
Код:
#include <Constants.au3>
#include <GUIConstantsEx.au3>
#include <GUIListBox.au3>
#include <WindowsConstants.au3>
#Include <File.au3>

;путь к любому текстовому логу
Local Const $sReceive = "x:\Log\receive.log"

$Receive = FileOpen($sReceive, 0)
$hLinesR = _FileCountLines($sReceive)


$Form1 = GUICreate("Монитор логов", 640, 480, 100, 50, BitOR($WS_MAXIMIZEBOX,$WS_MINIMIZEBOX,$WS_SIZEBOX,$WS_THICKFRAME,$WS_SYSMENU,$WS_CAPTION,$WS_OVERLAPPEDWINDOW,$WS_TILEDWINDOW,$WS_POPUP,$WS_POPUPWINDOW,$WS_GROUP,$WS_TABSTOP,$WS_BORDER,$WS_CLIPSIBLINGS))
$ListR = GUICtrlCreateList("", 5, 30, 630, 450, BitXOR($LBS_NOSEL, $WS_VSCROLL,$WS_HSCROLL))
GUICtrlSetLimit(-1, 1300)
GUISetState(@SW_SHOW)

;доб существующих последних 10-ти строк лога в лист
$r = 0
$nFilePosR = 0
While $r < $hLinesR
   $r = $r+1
   FileSetPos($Receive, $nFilePosR, $FILE_BEGIN)
   GUICtrlSetData ( $ListR, $r & '. '& FileReadLine ($Receive, $r) )
   $nFilePosR = FileGetPos ($Receive)
WEnd
_GUICtrlListBox_SetCaretIndex($ListR, $r)

AdlibRegister ( '_AddLine', 1000)

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch
WEnd

Func _AddLine()
   ;добавление новых строк в ресив лог
			While $hLinesR < _FileCountLines($sReceive)
			   $hLinesR = $hLinesR + 1
			FileSetPos($Receive, $nFilePosR, $FILE_BEGIN)
			GUICtrlSetData ( $ListR, $hLinesR & '.-'& FileReadLine ( $Receive, $hLinesR) )
			$nFilePosR = FileGetPos ($Receive)
			_GUICtrlListBox_SetCaretIndex($ListR, $hLinesR)
			WEnd
EndFunc
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
kosjachok
У меня так достаточно быстро отрабатывает:
Код:
$sResume = ''
$iTimeout = TimerInit()
$hFile = FileOpen(@ScriptDir & '\Test.txt', 0)

$sText = FileRead($hFile)
$aText = StringSplit($sText, @LF)
For $i = $aText[0] - 9 To $aText[0]
	$sResume &= 'Строка № ' & $i & ' - ' & $aText[$i] & @LF
Next
$iTime = Round(TimerDiff($iTimeout) / 1000, 2) & " сек."
MsgBox(0, $iTime, $sResume)
Файл Test.txt у меня на 80000 строк размером 2,5 Мб.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
madmasles
тоже не панацея. не всякий файл можно поместить в память. но главный вопрос, зачем помещать в память 100%*(FileSize - Sizeof10Lines)/FileSize файла, если на практике используется только 100%*Sizeof10Lines/FileSize ?
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Kaster
Согласен. :smile:
 
Автор
K

kosjachok

Новичок
Сообщения
30
Репутация
3
Слепил всё до кучи, вот что получилось:
Код:
#Include <Array.au3>
#include <Constants.au3>
#include <GUIConstantsEx.au3>
#include <GUIListBox.au3>
#include <WindowsConstants.au3>
#Include <File.au3>

$sFile = 'd:\ххх.log'

$Form1 = GUICreate("Монитор логов", 640, 480, 100, 50, BitOR($WS_MAXIMIZEBOX,$WS_MINIMIZEBOX,$WS_SIZEBOX,$WS_THICKFRAME,$WS_SYSMENU,$WS_CAPTION,$WS_OVERLAPPEDWINDOW,$WS_TILEDWINDOW,$WS_POPUP,$WS_POPUPWINDOW,$WS_GROUP,$WS_TABSTOP,$WS_BORDER,$WS_CLIPSIBLINGS))
$ListR = GUICtrlCreateList("", 5, 30, 630, 450, BitXOR($LBS_NOSEL, $WS_VSCROLL,$WS_HSCROLL))
GUICtrlSetLimit(-1, 1300)
GUISetState(@SW_SHOW)

$aListR = _LogList($sFile, $ListR)

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch
	  
	 $aListR = _LogListUpd($sFile, $ListR, $aListR)
WEnd

Func _LogList($sFileX, $hListX )

$hFile = FileOpen($sFileX, 0)
$nSize = FileGetSize($sFileX)
If $nSize > 10000 Then 
   $nSize = $nSize-5000
Else
   $nSize = 0
EndIf
FileSetPos ( $hFile, $nSize, 0 )
$sText = FileRead($hFile)
$aText = StringSplit($sText, @LF)
$iS = _FileCountLines($sFileX) - $aText[0] -1
For $i = 2 To $aText[0]
   If $aText[$i] > "" Then 
	$iS += 1
   ; $sResume &= 'Строка № ' & $i & ' - ' & $aText[$i] & @LF
	GUICtrlSetData ( $hListX, 'Строка № ' & $iS & ' - ' & $aText[$i])
	EndIf
 Next
$nLines = _GUICtrlListBox_GetCount($hListX)
 _GUICtrlListBox_SetCaretIndex($hListX, $nLines)
 FileClose ($hFile)
 Dim $aVar[4]
 $aVar[0] = $nSize
 $aVar[1] = $nLines
 $aVar[2] = $iS
 Return ($aVar)
 EndFunc
 
 
Func _LogListUpd($sFileX, $hListX, $aVar)
$nSize2 = FileGetSize($sFileX)
$nSize = $aVar[0]
$nLines = $aVar[1]
$iS = $aVar[2]
	  If $nSize < $nSize2 Then
	  $hFile = FileOpen($sFileX, 0)
	  FileSetPos ( $hFile, $nSize, 0 )
	  $sText = FileRead($hFile)
	  $aText = StringSplit($sText, @LF)
		 For $i2 = 1 To $aText[0]
			If $aText[$i2] > "" Then 
			$iS += 1
			$nLines += 1 
			;$sResume &= 'Строка № ' & $i & ' - ' & $aText[$i] & @LF
			GUICtrlSetData ( $hListX, 'Строка № ' & $iS & ' - ' & $aText[$i2])
			_GUICtrlListBox_SetCaretIndex($hListX, $nLines)
			EndIf
		 Next
	  FileClose ($hFile)	  
	  $nSize = FileGetSize($sFileX)
	  EndIf	  
Dim $aVar2[4]
 $aVar2[0] = $nSize
 $aVar2[1] = $nLines
 $aVar2[2] = $iS
Return ($aVar2)
EndFunc

Что я могу сказать - теперь успевает обрабатывать 3 лога одновременно! :laugh: Всем спасибо!
 

damien2008

Осваивающий
Сообщения
178
Репутация
34
очень сильно извиняюсь за оффтоп, но все-таки.

текстовый документ из 6 строк некорректно обрабатывается
из
Код:
первая строка, повторится ведь? )
вторая строка, тоже ? О_о
третья строка, тоже ? О_о
ничего не понимаю
как оно работает?
)))

получаем следующее:

Autoit 3.3.8.1
 
Автор
K

kosjachok

Новичок
Сообщения
30
Репутация
3
Смени в первой функции
Код:
$aVar[0] = $nSize

на
Код:
$aVar[0] = FileGetSize($sFileX)


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

damien2008

Осваивающий
Сообщения
178
Репутация
34
первая строка не тут случайно? : 8)
Код:
For $i = 2 To $aText[0]


Код:
For $i = 1 To $aText[0]
 
Верх