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éambuleEn 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
RemarquesLes 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 courantesLes 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
Private Sub Command1_Click()
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 ? :
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
On Error GoTo ReadFileToBuffer_ERR
f = FreeFile Open szFileName For Binary As #f buffer = Space$(LOF(f)) Get #f, , buffer Close #f ReadFileToBuffer = buffer ReadFileToBuffer_END: Exit Function ReadFileToBuffer_ERR: 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
Private Sub Command2_Click()
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é.
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 nbOcc = nbOcc + 1 If (nbOcc = 1) Or (mode = 1) Then Else Print #f, t(i) End If Else Print #f, t(i) End If Next i Close #f End Sub
Private Sub Command3_Click()
Call RemoveLineFromFileByPattern("c:\publicdata\test.txt", "Bernard", 0) 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
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 nbOcc = nbOcc + 1 If (nbOcc = 1) Or (mode = 1) Then Print #f, NewValue Else Print #f, t(i) End If Else Print #f, t(i) End If Next i Close #f End Sub
Private Sub Command1_Click()
Call ReplaceLineFromFileByPattern("c:\publicdata\test.txt", "Bernard", "Louis", 0) 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 If Not (insertion_done) Then Print #f, NewValue End If Close #f End Sub
Private Sub Command5_Click()
Call InsertLineInFile("c:\publicdata\test.txt", 2, "François") Call InsertLineInFile("c:\publicdata\test.txt", 0, "Jean-Marc")
End Sub Limites d'utilisation, précautions utilesLimitesLes 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écautionsCette 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 : |