Astuces de recherche...
Home
- Accueil & nouveautés
- Les newsgroups VB
- Téléchargements
- L'équipe
- Nous contacter
- Liens
Rubriques
- Toutes les questions
- Affichage & graphismes
- Algorithmique
- API
- Base de registre
- Bases de données
- Contrôles
- Date & heure
- Déploiement
- Divers
- Erreurs & problèmes
- Fichiers & dossiers
- Généralités
- Impression
- Internet & mails
- Math
- Multimédia
- Réseaux
- Structures de données
- Texte & strings
- VB .Net
- VB Script
- VBA
- Windows

Question 184

Comment modifier un fichier texte ?

Il est fréquent de devoir modifier un fichier texte existant, que l'on doive ajouter, supprimer ou modifier une ou plusieurs lignes de ce fichier. Cet article donne quelques explications générales à sujet puis présente quelques fonctions permettant de réaliser ces tâches. Dans ce qui suit, nous utiliserons les accès fichiers de type Input, Output et Append. Remarque : Le type Random, utilisé pour gérer les fichiers séquentiels, n'est pas abordé dans cet article ; une note leur est consacré dans la section "Aller plus loin".

Préambule

En VB, il n'existe pas à proprement parler de méthodes permettant de modifier directement un fichier texte, à part pour lui ajouter des lignes à la fin (ouverture en mode "Append"). Pour modifier un fichier (texte), il faut donc procéder par étape, en suivant le mécanisme général suivant :

  • Ouverture du fichier existant en lecture et lecture des données en mémoire
  • Faire les modifications : ajout, suppression, modification, etc.
  • Sauvegarde des données modifiées sous le même nom de fichier que l'original

Remarques

Les exemples suivants sont tous fonctionnels et peuvent tous être utilisés directement. Pour la plupart, ils sont très généraux et ne sont donc pas particulièrement optimisés. L'idée est ici plus de faire une présentation générale et concrète des méthodes existantes. Le lecteur pourra ainsi aisément adapter si besoin les fonctions proposées pour les rendre plus performantes ou plus adaptées à ses besoins.

Afin de ne pas alourdir le code, les fonctions présentées ici ne sont pas sécurisées, en ce sens ou l'on ne teste pas systématiquement les cas d'erreur, comme on le ferait dans des conditions réelles. On peut se référer à l'article Comment lire rapidement un fichier texte ? pour un exemple de fonction comportant une bonne gestion d'erreur.

Exemples d'implémentation des fonctions les plus courantes

Les exemples suivants donnent une implémentation simple des tâches les plus courantes : Ajout en fin de fichier, Suppression, Modification et Insertion. Sur ces bases, on peut implémenter d'autres fonctions plus spécifiques si besoin est. On verra à la fin de cet article les limites de ces méthodes, ainsi que les précautions éventuelles à prendre.

Comment ajouter des lignes à la fin d'un fichier existant ?

Il s'agit là de la plus simple des modifications de fichier. En effet, VB dispose directement d'un mode d'ouverture de fichier permettant de faire cela, le mode "Append". Dans ce mode d'ouverture, un fichier existant est ouvert en mode "Ecriture". Tout ajout au fichier se fait automatiquement à la fin. La fonction suivante permet d'ajouter une ligne à un fichier. Note : avec Append, si le fichier n'existe pas, il est créé.

Private Sub AddLineToFile(ByVal FileName As String, ByVal NewLine As String)
    
    Dim f As Integer
    
    f = FreeFile
    Open FileName For Append As #f
        Print #f, NewLine
    Close #f
    
End Sub

' Exemple d'appel
Private Sub Command1_Click()

    ' ajoute la ligne "HELLO, WORLD" au fichier test.txt
    Call AddLineToFile("c:\publicdata\test.txt", "HELLO, WORLD")
    
End Sub

Comment supprimer une ligne d'un fichier, connaissant le numéro de ligne ?

La fonction suivante permet de modifier un fichier en supprimant la ligne dont le numéro est passé en paramètre. On considère dans cette fonction que la première ligne est la ligne numéro 1.

Le principe est de lire tout le fichier dans un buffer, puis de stocker les lignes du fichier dans un tableau. Ensuite, on ouvre le fichier en écriture et on écrit toutes les lignes sauf celle dont le numéro a été passé en paramètre. Ceci peut paraître un peu lourd, mais c'est le seul moyen de faire cela en VB. D'autre part, à part pour un fichier vraiment gigantesque, cette opération est très rapide.

Voici tout d'abord la fonction générale de lecture de fichier dans un buffer, telle que reprise depuis l'article Comment lire rapidement un fichier texte ? :

' Cette fonction lit le contenu du fichier szFileName et retourne
' ce contenu. En cas d'erreur, elle retourne une chaîne vide et
' renseigne le code d'erreur et la description de l'erreur
'
Private Function ReadFileToBuffer(ByVal szFileName As String, _
                                ByRef errCode As Integer, _
                                ByRef errString As String) As String
    Dim f As Integer
    Dim buffer As String

    ' trappe les erreurs
    On Error GoTo ReadFileToBuffer_ERR

    ' Ouverture du fichier en 'Binary'
    f = FreeFile
    Open szFileName For Binary As #f
        ' préallocation d'un buffer à la taille du fichier
        buffer = Space$(LOF(f))
        ' lecture complète du fichier
        Get #f, , buffer
    Close #f
    ReadFileToBuffer = buffer
ReadFileToBuffer_END:
    Exit Function
    
ReadFileToBuffer_ERR:
    ' Gestion d'erreur
    ReadFileToBuffer = ""
    errCode = Err.Number
    errString = Err.Description
    Resume ReadFileToBuffer_END
End Function

Et voici la fonction de suppression de ligne :

Private Sub RemoveLineFromFile(ByVal FileName As String, ByVal NumLine As Long)
    
    Dim f As Integer, errCode As Integer, errString As String
    Dim buffer As String
    Dim t() As String
    Dim i As Long
    
    buffer = ReadFileToBuffer(FileName, errCode, errString)
    t() = Split(buffer, vbCrLf)
    NumLine = NumLine - 1
    
    f = FreeFile
    Open FileName For Output As #f
        For i = 0 To UBound(t()) - 1
            If i <> NumLine Then
                Print #f, t(i)
            End If
        Next i
    Close #f
    
End Sub

' Exemple d'appel
Private Sub Command2_Click()

    ' Suppression de la deuxième ligne du fichier
    Call RemoveLineFromFile("c:\publicdata\test.txt", 2)
    
End Sub

Comment supprimer une ligne d'un fichier, sur base de la présence d'une sous-chaîne" ?

La fonction suivante permet de supprimer une ou plusieurs lignes d'un fichier, si la ou les lignes en question contiennent un motif ou pattern donné en paramètre. Le principe de fonctionnement est similaire à la fonction précédente : on lit l'entièreté du fichier, on le place dans un tableau, puis on parcourt ce tableau du premier au dernier élément et on n'écrit que les lignes qui ne contiennent pas le motif recherché.

'
' Si mode=0, supprime seulement la première occurrence de Pattern
' Si mode=1, supprime toutes les occurrences de pattern
Private Sub RemoveLineFromFileByPattern(ByVal FileName As String, _
                                       ByVal Pattern As String, _
                                       ByVal mode As Integer)
    
    Dim f As Integer, errCode As Integer, errString As String
    Dim buffer As String
    Dim t() As String
    Dim i As Long
    Dim nbOcc As Long
    
    buffer = ReadFileToBuffer(FileName, errCode, errString)
    t() = Split(buffer, vbCrLf)
    
    
    f = FreeFile
    Open FileName For Output As #f
        For i = 0 To UBound(t()) - 1
            If InStr(t(i), Pattern) > 0 Then
                ' si on trouve le pattern
                nbOcc = nbOcc + 1
                If (nbOcc = 1) Or (mode = 1) Then
                    ' on n'écrit pas la ligne
                Else
                    Print #f, t(i)
                End If
            Else
                Print #f, t(i)
            End If
        Next i
    Close #f
    
End Sub

' Exemple d'appel
Private Sub Command3_Click()

    ' Suppression de la première ligne contenant "Bernard"
    Call RemoveLineFromFileByPattern("c:\publicdata\test.txt", "Bernard", 0)
        
    ' Suppression de toutes les lignes contenant "Henri"
    Call RemoveLineFromFileByPattern("c:\publicdata\test.txt", "Henri", 1)
End Sub

Comment modifier une ligne d'un fichier, sur base de la présence d'une sous-chaîne" ?

Le principe ici va rester le même que pour la fonction précédente : On passe à la fonction un motif ou pattern à rechercher, ainsi que la ligne de remplacement. On substitue toutes les lignes contenant le pattern recherché par la ligne de remplacement.

Remarque : On notera que cette fonction ne remplace pas un motif par un motif de remplacement, mais va remplacer toute la ligne par le motif de remplacement. Ainsi, si le motif à rechercher est "Bernard" et le motif de remplacement est "ROBERT", alors une ligne contenant "un Saint-Bernard" devient "ROBERT".

Option Explicit

' Si mode=0, remplace seulement la première occurrence de Pattern
' Si mode=1, remplace toutes les occurrences de pattern
Private Sub ReplaceLineFromFileByPattern(ByVal FileName As String, _
                                       ByVal Pattern As String, _
                                       ByVal NewValue As String, _
                                       ByVal mode As Integer)
    
    Dim f As Integer, errCode As Integer, errString As String
    Dim buffer As String
    Dim t() As String
    Dim i As Long
    Dim nbOcc As Long
    
    buffer = ReadFileToBuffer(FileName, errCode, errString)
    t() = Split(buffer, vbCrLf)
        
    f = FreeFile
    Open FileName For Output As #f
        For i = 0 To UBound(t()) - 1
            If InStr(t(i), Pattern) > 0 Then
                ' Si on trouve le pattern
                nbOcc = nbOcc + 1
                If (nbOcc = 1) Or (mode = 1) Then
                    ' On remplace toute la ligne
                    Print #f, NewValue
                Else
                    Print #f, t(i)
                End If
            Else
                Print #f, t(i)
            End If
        Next i
    Close #f
    
End Sub

' Exemple d'appel
Private Sub Command1_Click()

    ' Remplacement de la première ligne contenant "Bernard" par "Louis"
    Call ReplaceLineFromFileByPattern("c:\publicdata\test.txt", "Bernard", "Louis", 0)
        
    ' Remplacement de toutes les lignes contenant "Robert" par "Denise"
    Call ReplaceLineFromFileByPattern("c:\publicdata\test.txt", "Robert", "Denise", 1)
End Sub

Comment insérer une ligne à une position donnée dans un fichier ?

Le même principe est employé ici : lecture du fichier dans un tableau, parcours du tableau pour l'écriture avec en plus l'insertion de la ligne passée en paramètre à la position voulue. Dans la fonction suivante, on passe en paramètre la position d'insertion sous la forme d'un numéro de ligne. Pour insérer une ligne en tête de fichier, on devra spécifier 0 (zéro) comme position d'insertion.

Private Sub InsertLineInFile(ByVal FileName As String, _
                            ByVal PositionInsertion As Long, _
                            ByVal NewValue As String)
    
    Dim f As Integer, errCode As Integer, errString As String
    Dim buffer As String
    Dim t() As String
    Dim i As Long
    Dim insertion_done As Boolean
    
    buffer = ReadFileToBuffer(FileName, errCode, errString)
    t() = Split(buffer, vbCrLf)
    
    
    f = FreeFile
    Open FileName For Output As #f
        For i = 0 To UBound(t()) - 1
            If (i >= PositionInsertion) And Not (insertion_done) Then
                Print #f, NewValue
                insertion_done = True
            End If
            Print #f, t(i)
        Next i
        ' Insertion à la fin si pas encore fait
        If Not (insertion_done) Then
            Print #f, NewValue
        End If
    Close #f
    
End Sub

' Exemple d'appel
Private Sub Command5_Click()

    ' Insertion de "FRANCOIS" après la 2eme ligne (donc en ligne 3)
    Call InsertLineInFile("c:\publicdata\test.txt", 2, "François")
    
    ' Insertion de "JEAN-MARC" en tête de fichier
    Call InsertLineInFile("c:\publicdata\test.txt", 0, "Jean-Marc")

End Sub

Limites d'utilisation, précautions utiles

Limites

Les fonctions présentées sont toutes basées sur le même principe de lecture préalable de l'entièreté du fichier, suivi d'une réécriture. Cette méthode est tout à fait valable pour la plupart des cas, quand le fichier à modifier à une taille raisonnable, typiquement quelques dizaines, voire quelques centaines de milliers de lignes. Au-delà (plusieurs millions de lignes), une gestion de données sous forme de fichier texte n'est sans doute pas la meilleure solution. Cela est discuté dans l'article connexe : Mon programme doit sauvegarder des données. Où peut-il le faire et comment ?.

On pourrait penser que cette méthode de lecture, parsing et ré-écriture offre de piètres performances. En réalité, les machines modernes sont telles (mémoire, CPU, contrôleurs disques) que ce type de méthode reste tout à fait utilisable dans la vaste majorité des cas.

Précautions
Cette méthode présente une faille de sécurité pour les données; en effet, on effectue une lecture du fichier initial, puis une modification en mémoire puis enfin une réécriture complète du fichier. C'est dans ce dernier point qu'est la faille : si le programme est interrompu exactement après la réouverture du fichier en Output et avant la fermeture finale par "Close", le fichier initial est perdu, ainsi que ses données. Il sera donc prudent (recommandé) de toujours procéder à une sauvegarde du fichier de départ avant tout appel à ces fonctions, afin de pouvoir restaurer l'état initial en cas d'incident. La problématique de la pérennité des données et de la résilience aux pannes dépasse le cadre de cet article.

Pour aller Plus loin

Voir aussi :

Date de publication : 06 mars 2008
Dernière modification : 06 mars 2008
Rubriques : Fichiers & dossiers
Mots-clés : fichier, fichiers, texte, modifier, changer, préserver, remplacer, lignes, ligne, Open, Random, Line Input, Input