je me suis penché sur la façon d’accéder et de rechercher une donnée contenue dans un fichier texte de plusieurs milliers de lignes, sans que ces manipulations ne prennent trop de temps.
le fichier que j'ai choisi pour ma recherche est le fichier regroupant l'ensemble des codes IATA (aéroportuaires) : ce petit code de trois lettre que l'on trouve sur son bagage à la sortie de l'avion.
La première idée (qui n'est pas mauvaise) consistait a mettre ce fichier dans un tableau en mémoire, de façon à ce que la recherche soit instantanée.
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <EditConstants.au3>
global $gui,$Input,$Label_aeroport,$arr, $file=@ScriptDir & "\codesnew.csv"
$gui = GUICreate("Codes Aéroports V 1.1", 730, 128, 232, 194)
$Input = GUICtrlCreateInput("", 16, 24, 30, 21)
GUICtrlCreateLabel("<--- Code Aéroportuaire : Ex: STN", 60, 24, 200, 21)
GUICtrlCreateLabel("Correspond à :", 16, 64, 76, 17)
$Label_aeroport = GUICtrlCreateLabel("", 104, 64, 608, 25)
$Group1 = GUICtrlCreateGroup("", 8, 8, 713, 105)
GUICtrlCreateLabel("Concept && dévellopement : Marc GRAZIANI", 500, 96, 220, 17)
GUICtrlCreateGroup("", -99, -99, 1, 1)
$Button_ok = GUICtrlCreateButton("OK", 648, 16, 65, 25)
$button_array = GUICtrlCreateButton("Liste",648,46,65,25)
$accEnter = GUICtrlCreateDummy()
Global $a_AccelKeys[1][2] = [["{ENTER}", $accEnter]]
GUISetAccelerators($a_AccelKeys)
If not FileExists($file) then
msgbox(64,"Erreur", "Fichier Codes.csv Manquant" & @CRLF & "Je quitte")
Exit
EndIf
Dim $sCSV = FileRead($file)
ProgressOn("Préparation","Chargement, veuillez patienter")
Local $arr = toArrayCsv($sCSV)
GUISetState(@SW_SHOW)
While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
Case $Button_ok
_trouve_code()
case $button_array
_ArrayDisplay($arr,"Codes Aéroports","|3",16)
Case $accEnter
If _GuiCtrlGetFocus($gui) = $Input Then
_trouve_code()
Else
GUISetAccelerators("")
ControlSend($gui, "", _GuiCtrlGetFocus($gui), "{ENTER}")
GUISetAccelerators($a_AccelKeys)
EndIf
EndSwitch
WEnd
Func _trouve_code()
$code=GUICtrlRead($Input)
$result=correspond($arr,$code)
GUICtrlsetdata($Label_aeroport,$result)
EndFunc
Func toArrayCsv($s)
Local $line = StringSplit($s,@CRLF,2+1) ; combien de ligne de mon fichier <> tableau
Local $maxCol = 1 ; nombre de colonne de depart
Local $a[UBound($line)][$maxCol] ; je crée un tableau de n ligne et de 1 colonne que je modifierai à ma guise
ProgressSet(0)
For $i = 0 To UBound($line)-1 ; parcours toutes les lignes
Local $tmp = StringSplit($line[$i],";",3) ; combien de colonnes pour la ligne n°i
If(UBound($tmp) > $maxCol ) then $maxCol = UBound($tmp) ; pour connaitre le nombre de colonnes
ReDim $a[UBound($line)][$maxCol] ; je redimensionne mon tableau aux bonnes dimensions
For $j = 0 To UBound($tmp)-1 ; je parcours cellule par cellule "de gauche a droite"
ProgressSet($i*100/UBound($line),"Lecture de la ligne : " & $i)
$a[$i][$j] = $tmp[$j] ; je remplis chaque cellule
Next
Next
ProgressOff()
Return $a
EndFunc
func correspond($array, $code)
$result = _ArrayFindAll($array, $code, 0, 0, 0, 1)
If IsArray($result) Then
For $i = 0 To UBound($array) - 1
$name = $array[$result[$i]][1]& ", " & $array[$result[$i]][2] & ", " & $array[$result[$i]][3] & " (Nom, Ville, Pays)"
return $name
Next
Else
Return "Non trouvé"
EndIf
EndFunc
Func _GuiCtrlGetFocus($hGui = "")
Local $InputID = ControlGetHandle($hGui, "", ControlGetFocus($hGui))
Return _ControlGetGuiID($InputID)
EndFunc ;==>_GuiCtrlGetFocus
Func _ControlGetGuiID($hCtrl)
Local $Result = DllCall("user32.dll", "int", "GetDlgCtrlID", "hwnd", $hCtrl)
If @error = 0 Then Return $Result[0]
Return SetError(1, 0, '')
EndFunc ;==>_ControlGetGuiID
Avantage : l'accès est immédiat
Inconvénient : au lancement, le programme est long a charger.
deuxième idée : faire parcourir le fichier a chaque requête
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <File.au3>
global $gui,$Input,$Label_aeroport,$arr,$file=@ScriptDir & "\codes.csv"
$gui = GUICreate("Codes Aéroports V 1.1", 730, 128, 232, 194)
$Input = GUICtrlCreateInput("", 16, 24, 30, 21)
GUICtrlCreateLabel("<--- Code Aéroportuaire : Ex: STN", 60, 24, 200, 21)
GUICtrlCreateLabel("Correspond à :", 16, 64, 76, 17)
$Label_aeroport = GUICtrlCreateLabel("", 104, 64, 608, 25)
$Group1 = GUICtrlCreateGroup("", 8, 8, 713, 105)
GUICtrlCreateLabel("Concept && dévellopement : Marc GRAZIANI", 500, 96, 220, 17)
GUICtrlCreateGroup("", -99, -99, 1, 1)
$Button_ok = GUICtrlCreateButton("OK", 648, 16, 65, 25)
If not FileExists($file) then
msgbox(64,"Erreur", "Fichier Codes.csv Manquant" & @CRLF & "Je quitte")
Exit
EndIf
HotKeySet("{enter}","_recherche_code")
GUISetState(@SW_SHOW)
While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
Case $Button_ok
_recherche_code()
EndSwitch
WEnd
Func _recherche_code()
$flag=0
guictrlsetdata($Label_aeroport,"")
$file_maxline = _FileCountLines($file)
$recherche_code = GUICtrlRead($Input)
$pc_liste = FileOpen($file, 0)
If $pc_liste = -1 Then
MsgBox(0, "Erreur", "Impossible d'ouvrir le fichier !")
Exit
EndIf
ProgressOn("Recherche","Je recherche... Patientez... ")
for $i = 1 to $file_maxline
ProgressSet($i * 100 / $file_maxline)
$line = FileReadLine($pc_liste,$i) ; on parcours chaque ligne du fichier TXT
If StringInStr(stringleft($line,3), $recherche_code) Then
$flag=1
$split = StringSplit($line,";")
GUICtrlsetdata($Label_aeroport,$split[2])
ProgressOff()
ExitLoop
EndIf
if $i=$file_maxline and $flag =0 Then
GUICtrlsetdata($Label_aeroport,"Je suis désolé, je ne trouve pas")
ProgressOff()
ExitLoop
EndIf
Next
FileClose($file)
EndFunc
avantage : le lancement du programme est immédiat
Inconvénient : en cas d'accès répété les temps de recherche sont longs.
troisième idée : transformer le fichier CSV en fichier ini contenant des balises et des labels. (solution retenue)
Les Codes IATA étant générés sur 3 lettres ou chiffres, il est possible de les ordonner alphabetiquemement et numeriquement. chaque balise regroupant les codes de sa lettre ou son chiffre.
#include <GUIConstantsEx.au3>
#include <EditConstants.au3>
global $gui,$Input,$Label_aeroport,$arr,$file=@ScriptDir & "\codes-IATA.ini"
$gui = GUICreate("Codes Aéroports V 1.3", 830, 128, 232, 194)
$Input = GUICtrlCreateInput("", 16, 24, 30, 21)
GUICtrlCreateLabel("<--- Code Aéroportuaire : Ex: STN", 60, 24, 200, 21)
GUICtrlCreateLabel("Correspond à (Nom, Ville, PAYS) : ", 16, 75, 170, 17)
$Label_aeroport = GUICtrlCreateLabel("", 190, 75, 608, 25)
$Group1 = GUICtrlCreateGroup("", 8, 8, 813, 105)
GUICtrlCreateLabel("Concept && dévellopement : Marc GRAZIANI", 600, 96, 220, 17)
GUICtrlCreateGroup("", -99, -99, 1, 1)
$Button_ok = GUICtrlCreateButton("OK", 748, 16, 65, 25)
$button_QUITTER = GUICtrlCreateButton("Quitter",748,46,65,25)
$accEnter = GUICtrlCreateDummy()
Global $a_AccelKeys[1][2] = [["{ENTER}", $accEnter]]
GUISetAccelerators($a_AccelKeys)
If not FileExists($file) then
msgbox(64,"Erreur", "Fichier " & $file & " Manquant" & @CRLF & "Je quitte")
Exit
EndIf
GUISetState(@SW_SHOW)
While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE, $button_QUITTER
Exit
Case $Button_ok
_recherche_code()
Case $accEnter
If _GuiCtrlGetFocus($gui) = $Input Then
_recherche_code()
Else
GUISetAccelerators("")
ControlSend($gui, "", _GuiCtrlGetFocus($gui), "{ENTER}")
GUISetAccelerators($a_AccelKeys)
EndIf
EndSwitch
WEnd
Func _recherche_code()
guictrlsetdata($Label_aeroport,"")
$recherche_code = GUICtrlRead($Input)
$lettre_recherche = StringLeft($recherche_code,1)
$result = IniRead($file, stringupper($lettre_recherche), stringleft($recherche_code,3),"")
If $result = "" then
GUICtrlsetdata($Label_aeroport,"Je suis désolé, je ne trouve pas")
Else
GUICtrlsetdata($Label_aeroport,$result)
EndIf
EndFunc
Func _GuiCtrlGetFocus($hGui = "")
Local $InputID = ControlGetHandle($hGui, "", ControlGetFocus($hGui))
Return _ControlGetGuiID($InputID)
EndFunc ;==>_GuiCtrlGetFocus
Func _ControlGetGuiID($hCtrl)
Local $Result = DllCall("user32.dll", "int", "GetDlgCtrlID", "hwnd", $hCtrl)
If @error = 0 Then Return $Result[0]
Return SetError(1, 0, '')
EndFunc ;==>_ControlGetGuiID
Avantage : ouverture et temps d'accès immédiats.
Inconvénients : demande la transformation du fichier CSV en INI
Je laisse cette petite recherche pour ceux que aimeraient faire de même et qui ne savent pas comme s'y prendre.... tout en sachant que certains sont bien meilleur que moi (qu'ils n’hésitent pas à modifier et améliorer le code)