Page 1 sur 1

[R] Lenteurs avec FileReadLine inversé

Posté : lun. 11 sept. 2017 16:08
par corrs78
Bonjour,
sans que je me l'explique l'operation de recherche d'une sous-chaine dans un fichier est 100x plus long si je commence par parcourir le fichier depuis la dernière ligne.

Concrètement :

si j’exécute ce script, il met un temps fou à parcourir le fichier.
Nota : sur un fichier de 1000 lignes, c'est seulement 2x plus long, environ 2scds pour parcourir le fichier de la ligne 1000 à 1
(1scd pour traiter dans le sens "normal" 1 à 1000)
par contre, j'ai l'impression que ce delta est exponentiel.
Sur mon fichier log de 50 000 lignes je parcours une journée de log en moins de 1scd si je commence par le debut du fichier, mais si je commence par la fin alors là je parcours le meme nombre de lignes en 30scds

Code : Tout sélectionner

#include<File.au3>
$mot_cle = "test"

 $Fichier_log = FileOpen("c:\ressources\logon.log", 0)
	If $Fichier_log = -1 Then
		MsgBox(0, "Erreur", "Impossible d'ouvrir le fichier logon.log")
		Exit
	EndIf

For $i= _FileCountLines("c:\ressources\logon.log") to 1 step -1
  $line = FileReadLine($Fichier_log, $i-1)
	consoleWrite($line & "   " &$i&@CRLF)
    If StringInStr($line, $mot_cle) Then
			ConsoleWrite($line)
	EndIf
Next
FileClose($Fichier_log)
j'ai bien tenté avec While > Wend, meme problème.

Help :)

Re: [...] Lenteurs avec FileReadLine inversé

Posté : lun. 11 sept. 2017 21:39
par TomAijerrie
Enregistre le nombre de ligne dans une variable, et utilise cette variable, ça évitera de rééxécuter la fonction _FileCountLines à chaque fois (50 000 fois environ)
Je ne suis pas sûr que ça vienne de là, mais c'est une piste.

J'ai souvent travaillé avec de gros fichers de logs, et ton script est très similaire aux miens. Sauf que j'utilise Do...Until ou While..Wend et que je sors une fois que j'ai la ligne qu'il me faut, ou une fois que la ligne que je veux lire n'existe pas (un petit "If @error then exitloop" apres le FileReadLine), comme ça, pas besoin de connaitre le nombre de ligne.

Re: [...] Lenteurs avec FileReadLine inversé

Posté : lun. 11 sept. 2017 21:53
par corrs78
Merci de ta réponse. Je vais tester ça dès demain.

Précision(je ne l'ai pas affiché ici, pour simplifier le code) : l'objectif est d'afficher les 5 dernières lignes ou le mot clé est trouvé. Concrètement je veux afficher les 5derniers logs d'une machine.

Re: [...] Lenteurs avec FileReadLine inversé

Posté : lun. 11 sept. 2017 22:57
par orax
_FileCountLines n'est exécuté qu'une seule fois (j'ai vérifié). C'est FileReadLine qui est long (dans ce cas particulier). Il y a aussi le ConsoleWrite qui affiche chaque ligne qui ralentit le script.

2 exemples à tester :

Code : Tout sélectionner

#include <File.au3>
#include <Array.au3>
$mot_cle = "test"

$t = TimerInit()
$aLines = FileReadToArray("c:\ressources\logon.log")

For $i = @extended - 1 To 0 Step -1
	If StringInStr($aLines[$i], $mot_cle) Then
		ConsoleWrite($i & " " & $aLines[$i] & @CRLF)
	EndIf
Next
ConsoleWrite(TimerDiff($t) & @CRLF)

$t = TimerInit()
$sFile = FileRead("c:\ressources\logon.log")
$a = StringRegExp($sFile, "test.*\R", 3)
ConsoleWrite(TimerDiff($t) & @CRLF)
_ArrayDisplay($a)

Re: [...] Lenteurs avec FileReadLine inversé

Posté : lun. 11 sept. 2017 23:31
par TomAijerrie
Ces deux scripts fonctionnent bien pour des petits et moyens fichiers, mais perso, j'ai un PC en mousse, et quand j'ai testé avec un log plus gros que ma RAM libre, ça a crash...
Mais ce n'est pas moi qui va utiliser ce script, donc si son PC est plus costaux que le mien, et que ça marche, tant mieux.

Et je confirme que ConsoleWrite ralenti beaucoup. On pourrait plutôt ajouter les lignes dans une variable et tout afficher à la fin.

Re: [...] Lenteurs avec FileReadLine inversé

Posté : mar. 12 sept. 2017 03:09
par jchd
Mieux vaudrait une approche plus efficace :

Code : Tout sélectionner

#include <File.au3>

Local $sFichier = "testcle.txt"	;"c:\ressources\logon.log"
Local $sMot_cle = "test"

Local $sText = FileRead($sFichier)
If @error Then
	MsgBox(0, "Erreur", "Impossible d'ouvrir le fichier logon.log")
Else
	Local $aLines = StringRegExp($sText, "(?m)(^.*\Q" & $sMot_cle & "\E.*$)", 3)
    If Not @error Then
		For $i = (UBound($aLines) >= 5 ? UBound($aLines) - 5 : 0) To UBound($aLines) - 1
			ConsoleWrite($aLines[$i] & @LF)
		Next
	EndIf
EndIf

Re: [...] Lenteurs avec FileReadLine inversé

Posté : mar. 12 sept. 2017 11:33
par corrs78
jchd a écrit : mar. 12 sept. 2017 03:09 Mieux vaudrait une approche plus efficace :

Code : Tout sélectionner

#include <File.au3>

Local $sFichier = "testcle.txt"	;"c:\ressources\logon.log"
Local $sMot_cle = "test"

Local $sText = FileRead($sFichier)
If @error Then
	MsgBox(0, "Erreur", "Impossible d'ouvrir le fichier logon.log")
Else
	Local $aLines = StringRegExp($sText, "(?m)(^.*\Q" & $sMot_cle & "\E.*$)", 3)
    If Not @error Then
		For $i = (UBound($aLines) >= 5 ? UBound($aLines) - 5 : 0) To UBound($aLines) - 1
			ConsoleWrite($aLines[$i] & @LF)
		Next
	EndIf
EndIf
Merci jchd, cette méthode est en effet la plus efficace. Merci pour la RegExp, car je suis nul dans ce domaine :?
mon résultat est affiché instantanément dans un Richedit.
Par contre j'ai fait une condition "sans limite de résultats" , j'ai modifié le For de cette façon , ça ne fonctionne pas . j'ai raté un truc ?

Code : Tout sélectionner

For $i = UBound($aLines) To UBound($aLines) - 1
Merci

Re: [...] Lenteurs avec FileReadLine inversé

Posté : mar. 12 sept. 2017 14:27
par jchd
Dans ce cas :

Code : Tout sélectionner

For $i = 0 To UBound($aLines) - 1
et on obtient toutes les occurences.

Re: [...] Lenteurs avec FileReadLine inversé

Posté : mar. 12 sept. 2017 16:55
par corrs78
Merci à tous. c'est parfait. :bisou:

Re: [R] Lenteurs avec FileReadLine inversé

Posté : mar. 12 sept. 2017 20:04
par jchd
Seul (petit) bémol : il ne faut pas que le mot-clé contienne \E, sinon il faut une circonvolution supplémentaire. J'ai pensé que c'était peu probable pour un nom de machine.

Re: [R] Lenteurs avec FileReadLine inversé

Posté : mar. 12 sept. 2017 21:02
par corrs78
Ne t'inquiète pas. Aucune chance dans mon log. Encore merci de ton aide.

Re: [R] Lenteurs avec FileReadLine inversé

Posté : jeu. 14 sept. 2017 17:12
par corrs78
jchd a écrit : mar. 12 sept. 2017 20:04 Seul (petit) bémol : il ne faut pas que le mot-clé contienne \E, sinon il faut une circonvolution supplémentaire. J'ai pensé que c'était peu probable pour un nom de machine.
Par contre je viens de me rendre un compte de deux choses
la casse est prise en compte. et vu que je cherche des noms propre, prénom, version d'OS c'est un problème.

il faudrait aussi que je puisse intégrer un délimiteur de texte. car si je cherche l'IP : "192.168.1.1" j'obtiens toutes les IP en 1***
par exemple ajouter des guillemets en debut et fin de chaine pour spécifier l'exclusivité de la recherche.

c'est possible d'intégrer ces paramètres dans ta RegExp


merci beaucoup.

Re: [R] Lenteurs avec FileReadLine inversé

Posté : jeu. 14 sept. 2017 20:55
par jchd
Ah, une cible mouvante ! OK, mais je voudrais aussi que ça sorte ceci et pas cela... OK ça marche, mais sauf quand...

Une regexp est un programme et tout développement en spirale dérape en temps, énergie, bugs et complexité inutile.

Pour ignorer la casse :

Code : Tout sélectionner

StringRegExp($sText, "(?im)(^.*\Q" & $sMot_cle & "\E.*$)", 3)
L'option i en tête de regexp convient, du moins pour la plage ASCII A-Z <--> a-z. Si on veut que "Строка символов" ("Chaîne de caractères", en russe) soit reconnu égal à "СТРОКА СИМВОЛОВ" il faut ajouter (*UCP) en tête.

Code : Tout sélectionner

StringRegExp($sText, "(*UCP)(?im)(^.*\Q" & $sMot_cle & "\E.*$)", 3)
par exemple ajouter des guillemets en debut et fin de chaine pour spécifier l'exclusivité de la recherche.
Ce n'est pas une spécification, ça.
Ce qui compte c'est ce qu'il ne doit pas y avoir après "192.168.1.1" dans le log. Mais là ce n'est plus avec une variable motclé purement litérale qu'on peut faire ça.

Evalue l'ensemble de tes besoins et produit une spécification complète à partir de laquelle tu pourras être conseillé.