Lecture de fichier ligne à ligne

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Lecture de fichier ligne à ligne

Message par Progi1984 »

Code : Tout sélectionner

DeleteFile(GetTemporaryDirectory()+ "filetest.txt")
If CreateFile(0, GetTemporaryDirectory()+ "filetest.txt")
  For Inc = 0 To 40000
    ;WriteString(0, LSet("", Random(255), "a")+Chr(10)) ; Linux
    ;WriteString(0, LSet("", Random(255), "b")+Chr(13)) ; MacOS
    WriteString(0, LSet("", Random(255), "c")+Chr(13)+Chr(10)) ; Windows
  Next
  CloseFile(0)
EndIf
ProcedureDLL.s PeekLine(*BufMem = 0, BufLen = 0)
	Protected *ptrChar.Character, *ptrStr.Character, *ptrEof
	Protected lLength.l
	Protected cChar.c, cCharBis.c
	Static MemOffset, MemLen, *MemBuf
	Static bSystem.b
	If *BufMem And BufLen
	  	*MemBuf = *BufMem
	  	MemLen = BufLen
	  	MemOffset = 0
	EndIf
	If *MemBuf And MemLen
		*ptrChar = *MemBuf + MemOffset 
		*ptrEof = *MemBuf + MemLen
		*ptrStr = *ptrChar
		If MemOffset < MemLen
			While *ptrChar< *ptrEof
				cChar = *ptrChar\c
				*ptrChar = *ptrChar + SizeOf(Character)
        If cChar = 13
          Break
        EndIf
        If cChar = 10
          Break
        EndIf
        lLength + 1 				
			Wend
      If *ptrChar < *ptrEof
        cCharBis = *ptrChar\c
        If cCharBis + cChar = 23
          *ptrChar = *ptrChar + SizeOf(Character)
        EndIf
      EndIf 
			MemOffset = *ptrChar - *MemBuf
			ProcedureReturn PeekS(*ptrStr, lLength)
		Else
			ProcedureReturn Chr(1)
		EndIf
	Else
		ProcedureReturn Chr(1)
	EndIf
EndProcedure

lNbLines = 0
TimeStart.l = ElapsedMilliseconds()
Global Stream.l = ReadFile(#PB_Any, GetTemporaryDirectory()+ "filetest.txt")
If Stream
  MemBufferLen = Lof(Stream)
  If MemBufferLen
    *MemBuffer = AllocateMemory(MemBufferLen)
    If *MemBuffer
      If ReadData(Stream, *MemBuffer, MemBufferLen) = MemBufferLen
        CloseFile(Stream)
        Line.s = PeekLine(*MemBuffer, MemBufferLen)
        Repeat
          lNbLines + 1
          ; Debug Line
          Line = PeekLine()
        Until Line = Chr(1)
        FreeMemory(*MemBuffer)
      EndIf
    EndIf
  EndIf
  
EndIf
TimeEnd.l = ElapsedMilliseconds()
Debug TimeStart
Debug TimeEnd
Debug "Time #1 > " + Str(TimeEnd - TimeStart)+"ms"
Debug lNbLines

lNbLines = 0
TimeStart.l = ElapsedMilliseconds()
Global Stream.l = ReadFile(#PB_Any, GetTemporaryDirectory()+ "filetest.txt")
If Stream
  MemBufferLen = Lof(Stream)
  If MemBufferLen
    *MemBuffer = AllocateMemory(MemBufferLen)
    If *MemBuffer
      If ReadData(Stream, *MemBuffer, MemBufferLen) = MemBufferLen
        FileContent.s = PeekS(*MemBuffer, MemBufferLen)
      EndIf
      CloseFile(Stream)
      FreeMemory(*MemBuffer)
    EndIf
  EndIf
  For Inc = 0 To CountString(FileContent, Chr(13)) - 1
    Line = StringField(FileContent, Inc +1, Chr(13))
    Line = RemoveString(Line, Chr(13))
    Line = RemoveString(Line, Chr(10))
    lNbLines + 1
    ; Debug Line
  Next
EndIf
TimeEnd.l = ElapsedMilliseconds()
Debug TimeStart
Debug TimeEnd
Debug "Time #2 > " + Str(TimeEnd - TimeStart)+"ms"
Debug lNbLines
Et ca permet de gagner un peu plus de temps que de lire ligne à ligne un fichier via StringField. Un gain de 181%.

Code : Tout sélectionner

4080146
4082470
Time #1 > 2324ms
4082470
4503776
Time #2 > 421306ms
Un grand merci à Gnozal pour le code initial.

[EDIT] Amélioré pour pouvoir traiter les fins de ligne Windows, MacOs et Linux, sur n'importe quel système
Dernière modification par Progi1984 le dim. 29/mars/2009 0:07, modifié 1 fois.
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Je pense qu'une méthode plus sûre est souhaitable. Notamment récupérer le contenu du fichier par morceau de 16Ko (ou plus ou moins, c'est arbitraire), puis extraire les lignes. ça peut sembler grotesque et lourd mais dans le cas de très gros fichiers texte (> 500 Mégas), ben c'est plus cool de remplir la mémoire petit à petit.

Sinon, dans le cas de la plupart des fichiers texte, c'est une très bonne astuce. Merci pour les comparatifs.
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Message par Progi1984 »

Attention : c'est une méthode !

Si tu penses en avoir une autre, hésites pas :) Ca permettra d'améliorer le débat.
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Euh... C'est quoi le débat?!? Qu'est-ce que tu veux techniquement exécuter, que je ne me retrouve pas "hors sujet" !?
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Message par Progi1984 »

"Débat", dsl, est un mot que j'utilise à tort et raison.

La technique est un lecture ligne à ligne d'un fichier de type texte.
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Message par Kwai chang caine »

Genial PROGI ça c'est une super idée 8)
C'est vrai, que ce genre de code, les aficionados de l'utilitaire, y en ont tres tres souvent besoin.
La recherche dans un fichier texte, ou la lecture de celui ci.

C'est vrai que quand je vois, la rapidité que met EXCEL pour trouver un mot, ou bien une base de donnée, malgré que j'aime pas pas trop crosoft, je doit reconnaitre que c'est impressionant.

Evidement il couplent plusieurs methodes, pour arriver a ce phenomene, je suppose, l'indexation, la recherche dichotomique, et encore plein d'autres que je ne connais pas.
Mais bon ça reste une prouesse.

Merci d'avoir eu cette idée
Esperons que toi et les autres cerveaux de forum, s'interesserons à ce projet, et apporterons une pierre a cet edifice.
Et pourquoi pas etre plus rapide qu'ACCESS :D, qui je crois est loin d'etre le meilleur :roll:
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Oui ben pour demander l'eau pure, il ne faut pas uriner à la source. Visiblement, tu n'as pas vu qu'il y avait de beaux ruisseaux.

Pour ma part de contribution sur ce forum, je vais freiner significativement quelque temps.

J'espère qu'à ma venue, je pourrais avoir une discussion clean sur le sujet des bases de données. Grâce à nombre d'entre vous (que je taquine), je suis très bien guidé pour apprendre beaucoup de choses, et cela sans limite. C'est extrêmement enrichissant. Sans cette communication, une multitude de questions dont les réponses sont à ma portée ne m'auraient pas effleuré l'esprit et donc fait évoluer.

Bonne continuation,
Aux prochaines nouvelles!

Ollivier
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Message par Progi1984 »

@Ollivier, en réponse à ton MP,

cette lecture ligne à ligne d'un fichier est pour remplacé la technique du StringField (http://code.google.com/p/moebius-pb/sou ... Step2.pb#8) que j'utilise actuellement dans Moebius.
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Bon, je vais "freiner le freinage inutile". Toi, t'y es pour rien!

Pour le projet Moëbius (ça rend sûrement hommage à un tech-raveur récent orné d'un ruban blanc mal mis autour du crâne pour être facilement repéré par ses potes en pleine foule quand ces derniers reviennent sur la piste avec la tournée de bière*), je n'ai pas trop suivi et ton code me parle difficilement (Je crois que Gutemberg a découvert un truc qu'il a nommé alinéa en fredonnant "podom, podom..." durant une mixion très anodine).

Donc, une chose majeure que j'ignore sans rentrer dans trop de détails techniques c'est l'échelle de lecture : 1 fichiers à la fois? 1 gros fichiers? Plusieurs fichiers? Voire énormément de fichier? Woilà déjà ces questions débroussaillent le terrain.

Pour la technique reprise de Gnozal c'est très bien. Il manquera juste une optimisation de trois fois rien.

Ollivier

*: Las autoritades adviertent : The abuse of the alcohol is dangerous for the faithful. Please drink slowly and take Aspirine if headache.
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Message par Progi1984 »

A mon grand délire, je ne connais pas ce tech raveur.

Le problème est que les tabulations ne s'affichent pas en version web du code mais s'affiche bien en local :).

Le fichier est un seul et (souvent) gros fichier à la fois (le purebasic.asm (code généré par purebasic en mode commenté) environ 45000 lignes.

Le travail que je fais est la plupart du temps des extractions de chaines dans la ligne pour faire des tests (si la chaine contient macro, etc...)
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Progi1984 a écrit :A mon grand délire, je ne connais pas ce tech raveur.
Au plaisir!

lNbLines contient le nombre de lignes
*Ch\Chn[N] contient la Nième chaîne

Bon courage pour ton projet!

Code : Tout sélectionner

DeleteFile(GetTemporaryDirectory()+ "filetest.txt")
If CreateFile(0, GetTemporaryDirectory()+ "filetest.txt")
  For Inc = 0 To 40000
    WriteString(0, LSet("", Random(255), Chr(65 + Random(25) ) ) + "Pif" + Chr(13)+Chr(10)) ; Windows
  Next
  CloseFile(0)
EndIf

ProcedureDLL.s PeekLine(*BufMem = 0, BufLen = 0)
   Protected *ptrChar.Character, *ptrStr.Character, *ptrEof
   Protected lLength.l
   Protected cChar.c, cCharBis.c
   Static MemOffset, MemLen, *MemBuf
   Static bSystem.b
   If *BufMem And BufLen
        *MemBuf = *BufMem
        MemLen = BufLen
        MemOffset = 0
   EndIf
   If *MemBuf And MemLen
      *ptrChar = *MemBuf + MemOffset
      *ptrEof = *MemBuf + MemLen
      *ptrStr = *ptrChar
      If MemOffset < MemLen
         While *ptrChar< *ptrEof
            cChar = *ptrChar\c
            *ptrChar = *ptrChar + SizeOf(Character)
        If cChar = 13
          Break
        EndIf
        If cChar = 10
          Break
        EndIf
        lLength + 1             
         Wend
      If *ptrChar < *ptrEof
        cCharBis = *ptrChar\c
        If cCharBis + cChar = 23
          *ptrChar = *ptrChar + SizeOf(Character)
        EndIf
      EndIf
         MemOffset = *ptrChar - *MemBuf
         ProcedureReturn PeekS(*ptrStr, lLength)
      Else
         ProcedureReturn Chr(1)
      EndIf
   Else
      ProcedureReturn Chr(1)
   EndIf
EndProcedure

lNbLines = 0
TimeStart.l = ElapsedMilliseconds()
Global Stream.l = ReadFile(#PB_Any, GetTemporaryDirectory()+ "filetest.txt")
If Stream
  MemBufferLen = Lof(Stream)
  If MemBufferLen
    *MemBuffer = AllocateMemory(MemBufferLen)
    If *MemBuffer
      If ReadData(Stream, *MemBuffer, MemBufferLen) = MemBufferLen
        CloseFile(Stream)
        Line.s = PeekLine(*MemBuffer, MemBufferLen)
        Repeat
          lNbLines + 1
          ; Debug Line
          Line = PeekLine()
        Until Line = Chr(1)
        FreeMemory(*MemBuffer)
      EndIf
    EndIf
  EndIf
 
EndIf
TimeEnd.l = ElapsedMilliseconds()
XTime = TimeEnd - TimeStart

; *** Test suivant!
Test:
Structure Chaine
   Chn.S[1 << 24]
EndStructure

Define *Ch.Chaine
Define LongueurMoyenne.I = 20 ; (en caractères par ligne)
Define MaxChaine.I
Define *Curseur
Define *MaxBuffer

   TimeStart = ElapsedMilliseconds()
   lNbLines = 0
   Stream = ReadFile(#PB_Any, GetTemporaryDirectory()+ "filetest.txt")
   If Stream
      MemBufferLen = Lof(Stream)
      MaxChaine = MemBufferLen / LongueurMoyenne
      *Ch = AllocateMemory(MaxChaine * SizeOf(integer) )
      *MemBuffer = AllocateMemory(MemBufferLen)
      *MaxBuffer = *MemBuffer + MemBufferLen - 1
      If ReadData(Stream, *MemBuffer, MemBufferLen) = MemBufferLen
         CloseFile(Stream)
         *Curseur = *MemBuffer

         ! mov ebp, [p_Ch]
         ! mov edi, [p_MemBuffer]
         ! mov esi, [p_MaxBuffer]
Repete:
         ! mov ebx, edi
         ! mov ecx, esi
         ! sub ecx, edi
         ! inc ecx
         
         ! mov eax, 13
         ! cld
         ! repne scasb
         
         ! dec edi
         ! mov byte [edi], 0
         
         ! mov [ebp], ebx
         ! add ebp, 4
         ! add edi, 2
         ! cmp edi, esi
         ! jb l_repete
         
         ! mov [v_lNbLines], ebp
         lNbLines - *Ch
         lNbLines >> 2
      EndIf


   EndIf

   TimeEnd = ElapsedMilliseconds()
   MessageRequester("", "AVANT:" + Str(XTime)+ "ms    APRES:" + Str(TimeEnd - TimeStart) + "ms")
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Message par Progi1984 »

Moi, Monsieur ! Je dis ouah !!!!!!!!!

Temps passé pour 40000 lignes de 2042ms à 22ms !

Fonctionnel sous Linux.
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Message par Progi1984 »

J'ai essayé de mettre ton code en fonction mais j'ai un message d'erreur :

Code : Tout sélectionner

DeleteFile(GetTemporaryDirectory()+ "filetest.txt")
If CreateFile(0, GetTemporaryDirectory()+ "filetest.txt")
  For Inc = 0 To 10
    sContentLine.s = LSet("", Random(255), Chr(65 + Random(25) ) ) + "Pif" 
    WriteString(0, sContentLine+ Chr(13)+Chr(10)) ; Windows
    ;Debug sContentLine
  Next
  CloseFile(0)
EndIf

ProcedureDLL.s PeekLine(*BufMem = 0, BufLen = 0)
   Protected *ptrChar.Character, *ptrStr.Character, *ptrEof
   Protected lLength.l
   Protected cChar.c, cCharBis.c
   Static MemOffset, MemLen, *MemBuf
   Static bSystem.b
   If *BufMem And BufLen
        *MemBuf = *BufMem
        MemLen = BufLen
        MemOffset = 0
   EndIf
   If *MemBuf And MemLen
      *ptrChar = *MemBuf + MemOffset
      *ptrEof = *MemBuf + MemLen
      *ptrStr = *ptrChar
      If MemOffset < MemLen
         While *ptrChar< *ptrEof
            cChar = *ptrChar\c
            *ptrChar = *ptrChar + SizeOf(Character)
        If cChar = 13
          Break
        EndIf
        If cChar = 10
          Break
        EndIf
        lLength + 1             
         Wend
      If *ptrChar < *ptrEof
        cCharBis = *ptrChar\c
        If cCharBis + cChar = 23
          *ptrChar = *ptrChar + SizeOf(Character)
        EndIf
      EndIf
         MemOffset = *ptrChar - *MemBuf
         ProcedureReturn PeekS(*ptrStr, lLength)
      Else
         ProcedureReturn Chr(1)
      EndIf
   Else
      ProcedureReturn Chr(1)
   EndIf
EndProcedure

lNbLines = 0
TimeStart.l = ElapsedMilliseconds()
Global Stream.l = ReadFile(#PB_Any, GetTemporaryDirectory()+ "filetest.txt")
If Stream
  MemBufferLen = Lof(Stream)
  If MemBufferLen
    *MemBuffer = AllocateMemory(MemBufferLen)
    If *MemBuffer
      If ReadData(Stream, *MemBuffer, MemBufferLen) = MemBufferLen
        CloseFile(Stream)
        Line.s = PeekLine(*MemBuffer, MemBufferLen)
        Repeat
          lNbLines + 1
          ; Debug Line
          Line = PeekLine()
        Until Line = Chr(1)
        FreeMemory(*MemBuffer)
      EndIf
    EndIf
  EndIf
 
EndIf
TimeEnd.l = ElapsedMilliseconds()
XTime = TimeEnd - TimeStart

; *** Test suivant!
Structure Chaine
   Chn.S[1 << 24]
EndStructure
ProcedureDLL PeekFileLine(FileID.l, *ContentMem)
  Protected LenFile.l = Lof(FileID)
  Protected LenMid.I = 20 ; (en caractères par ligne)
  Protected StringMax.l, lNblines.l
  Protected *BufferMem, *BufferEnd, *Cursor
  
  StringMax    = LenFile / LenMid
  *ContentMem = AllocateMemory(StringMax * SizeOf(Integer))
  *BufferMem  = AllocateMemory(LenFile)
  *BufferEnd   = *MemBuffer + MemBufferLen - 1
  If ReadData(FileID, *BufferMem, LenFile) = LenFile
    *Cursor = *BufferMem
    ;EnableASM
      ! mov ebp, [p_ContentMem]
      ! mov edi, [p_BufferMem]
      ! mov esi, [p_BufferEnd]
      Repete:
      ! mov ebx, edi
      ! mov ecx, esi
      ! sub ecx, edi
      ! inc ecx
      
      ! mov eax, 13
      ! cld
      ! repne scasb
      
      ! dec edi
      ! mov byte [edi], 0
      
      ! mov [ebp], ebx
      ! add ebp, 4
      ! add edi, 2
      ! cmp edi, esi
      ! jb l_repete
      
      ! mov [v_lNbLines], ebp
    ;DisableASM
    lNbLines - *ContentMem
    ProcedureReturn lNbLines >> 2
  EndIf
EndProcedure

   TimeStart = ElapsedMilliseconds()
   NbLignes = 0
   Stream = ReadFile(#PB_Any, GetTemporaryDirectory()+ "filetest.txt")
   If Stream
      NbFiles = PeekFileLine(Stream, *Ch)
      Define *Chs.Chaine
      *Chs = *Ch
      CloseFile(Stream)
      ;For Inc = 0 To lNbLines -1
      ;  Debug *Ch\Chn[Inc]
      ;Next
   EndIf
    For Inc = 0 To NbLignes -1
      Debug *Chs\Chn[Inc]
    Next
   TimeEnd = ElapsedMilliseconds()
   MessageRequester("", "AVANT:" + Str(XTime)+ "ms    APRES:" + Str(TimeEnd - TimeStart) + "ms") 
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

A mon avis, il aurait été plus pratique que tu l'adaptes en Macro plutôt qu'en procédure (ou "fonction").

La difficulté principale est de savoir OU on place son code Asm : si c'est dans une procédure, c'est légèrement différent qu'en dehors de toute procédure.

Code : Tout sélectionner

Define MaVariable.L
Define *MonPointeur
! mov [v_MaVariable], eax ; MaVariable = registre eax
! mov [p_MonPointeur], eax ; *MonPointeur = registre eax

Code : Tout sélectionner

; Dans une procédure, il faut rajouter « p. » dans les champs d'accès [ xxx ]
Procedure MaProcedure(MaVariable1.L, *MonPointeur1)
   Protected MaVariable2.L
   Protected *MonPointeur2
   ! mov [p.v_MaVariable1], eax
   ! mov [p.v_MaVariable2], eax
   ! mov [p.p_MonPointeur1], eax
   ! mov [p.p_MonPointeur2], eax
EndProcedure
En attendant, si tu veux une procédure compatible DLL, voici le code migré en procédure. L'exemple crée un fichier texte de 15 millions de lignes (Environ 440Mo) et le charge en mémoire. Pour vérifier, j'affiche les trois premières lignes + la toute dernière ligne.

Petit Bémol important : ce sont des chaînes statiques. C'est-à-dire:

1) On peut les lire volontiers
2) On peut volontiers remplacer des caractères par d'autres sans modifier la taille.
3) On peut réduire la taille de la chaîne (suppression de caractère) en ayant conscience que les octets enlevés seront inutilisables à moins de réaugmenter la taille tout en évitant de "bouffer" les premiers caractères de la chaîne suivante.
4) Il est strictement interdit d'augmenter la taille d'origine au risque direct de "bouffer" les caractères de la ligne suivante

Aussi, cette méthode a un revers : elle n'utilise pas la gestion native d'espace pour chaîne (puisque c'est nous qui lui créons cet espace). Résultat: Les modifications habituelles d'une chaîne du type Chaine$ = blabla ou chaîne + blabla amène sûrement à un plantage (je n'ai pas testé). Il faut utiliser PokeS() et PeekS() pour modifier.

Ou bien tout simplement recopier ce tableau dans un vrai tableau dynamique. Dans ce cas, il y a quand même un laps de temps de transfert à considérer.

Je sappe un peu ton enthousiasme plus haut. Mais il vaut mieux que tu sois bien informé à ce sujet. On ne défie pas les fines techniques de Gnozal facilement !!!

Dernière remarque, un avantage d'un tel tableau avec toutes les données contigües est de pouvoir utiliser un système de recherche matériel économique en ressources mémoire.

Code : Tout sélectionner

#FileOpened   = 1
#MemAllocated = 2
#FileLoaded   = 4
#TableCreated = 8

Structure BuildArrayInfo

   FileName.S
   ExecStatus.I

   *SeqBegin
   *SeqEnd
   SeqSize.I ; En octet

   *ArrayTable
   *ArrayTableEnd
   ArrayTableSize.I ; (nombre de pointeurs)

   LineMeanLength.I ; Taille moyenne d'une ligne
   
EndStructure

Structure TextLineInfo
   TextLine.S[1 << 24]
EndStructure

Procedure.L LoadStringArray(*Info.BuildArrayInfo)

   Protected *SeqBegin
   Protected *SeqEnd
   Protected *TextLine
   Protected *TableEnd 
   Protected FileHnd.I
   Protected ExecStatus.I
   
   FileHnd = OpenFile(#PB_Any, *Info\FileName)
   If FileHnd
      
      ExecStatus | #FileOpened
      SeqSize.Q = Lof(FileHnd)
      *SeqBegin = AllocateMemory(SeqSize)
      
      If *SeqBegin
      
         ExecStatus | #MemAllocated
         *SeqEnd = *SeqBegin + SeqSize - 1
      
         If ReadData(FileHnd, *SeqBegin, SeqSize)
         
            ExecStatus | #FileLoaded
            CloseFile(FileHnd)
   
            *Info\SeqBegin = *SeqBegin
            *Info\SeqEnd = *SeqEnd
   
            If *Info\LineMeanLength = 0
               *Info\LineMeanLength = 10 ; Moyenne par défaut
            EndIf
   
            *Info\ArrayTableSize = ((*SeqEnd - *SeqBegin) / *Info\LineMeanLength) << 2
            Debug *Info\ArrayTableSize
            If *Info\ArrayTableSize < 1 << 8
               *Info\ArrayTableSize = 1 << 8
            EndIf
   
            ;Debug *Info\ArrayTableSize
            *Info\ArrayTable = AllocateMemory(*Info\ArrayTableSize)
            If *Info\ArrayTable

               ExecStatus | #TableCreated
               *TextLine = *Info\ArrayTable
               ! mov eax, 13            
               ! mov edi, [p.p_SeqBegin]
               ! mov ebp, [p.p_SeqEnd]
               ! mov edx, [p.p_TextLine]
   
               ! mov ecx, ebp ; ecx = EndSeq
               ! sub ecx, edi ;     - BeginSeq
               ! inc ecx      ;     + 1
LoadStringArrayLoop:
               ! mov ebx, edi ; Retient le début de la chaîne
               ! cld          ; Fixe le sens croissant (convention)
               ! repne scasb  ; Recherche le 13
   
               ! mov byte [edi - 1], 0 ; Remplace le 13 par le 0
               ! inc edi      ; Passe le 10
   
               ! mov [edx], ebx ; Copie l'adresse de début de ligne
               ! add edx, 4 ; ... Et passe au pointeur suivant
   
               ! cmp edi, ebp ; Fin de séquence ?
               ! jng l_loadstringarrayloop ; Non, continue
   
               ! mov [p.p_TableEnd], edx
               *Info\ArrayTableEnd = *TableEnd
               *Info\ArrayTableSize = *TableEnd - *TextLine
               ;Debug "***" + Str(*Info\ArrayTableSize)
               *Info\ArrayTable = ReAllocateMemory(*TextLine, *Info\ArrayTableSize)
            EndIf
         EndIf            
      EndIf
   EndIf
   *Info\ExecStatus = ExecStatus
EndProcedure 

   Define *TextLine.TextLineInfo
   Define BuildArrayInfo.BuildArrayInfo
   
   ;___________________________________________________
   X.S = "Voici le Bonjour" + Chr(13) + Chr(10) + "Ici, et bien c'est le Au revoir" + Chr(13) + Chr(10) + "Et là, ben c'est simplement A bientôt" + Chr(13) + Chr(10)
   CreateFile(0, "Test.TXT")
   For I = 0 To 5000000
      WriteData(0, @X, Len(X) )
   Next
   CloseFile(0)
   Delay(500)
   ;¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
   
   BuildArrayInfo\LineMeanLength = 20
   BuildArrayInfo\FileName = "Test.TXT"
   LoadStringArray(BuildArrayInfo)

   *TextLine = BuildArrayInfo\ArrayTable
   Debug *TextLine\TextLine[0]
   Debug *TextLine\TextLine[1]
   Debug *TextLine\TextLine[2]
   Debug *TextLine\TextLine[BuildArrayInfo\ArrayTableSize >> 2 - 1]
   Debug T1 - T0
   
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Message par Progi1984 »

Ouaip, là ca devient trop le bordel à mettre en place (dsl suis crevé donc direct). En fait, je cherche une fonction qui charge un fichier texte (avec possibilités de fin de ligne Windows, Linux ou MacOs) et me retourne rapidement les lignes (comme ici). Mais aussi, car j'en ai besoin, l'accès à ligne précédente ou à la ligne suivante.
Répondre