Ce cours est visible gratuitement en ligne.

Ce cours existe en livre papier.

Ce cours existe en eBook.

J'ai tout compris !
Apprenez à programmer en VB .NET

Apprenez à programmer en VB .NET

Mis à jour le lundi 24 juin 2013
  • 4 semaines
  • Facile

Eh bien, chers amis Zéros, on va attaquer un TP de taille ! Il nous fera développer un programme qui aura pour but d'effectuer des sauvegardes périodiques de dossiers spécifiés.

Je ne vous en dis pas plus, on attaque tout de suite.

Le cahier des charges

C'est parti pour le cahier des charges ! En premier lieu je vais vous décrire ce que notre programme sera susceptible de faire.

Tout d'abord ce programme est un programme d'auto-backup, autrement dit de sauvegarde automatique. Ce programme sera capable de sauvegarder périodiquement un ou des dossiers que nous spécifierons dans une liste.

Pour commencer nous n'allons pas chercher bien loin : nous allons juste créer un répertoire dans lequel nous entasserons nos sauvegardes (répertoire spécifié par l'utilisateur). Essayez de ranger et de trier les différentes sauvegardes, pourquoi pas avec la date et l'heure.

Je laisse libre cours à votre imagination, à vous de voir si une seconde fenêtre est préférable pour spécifier la configuration, etc.

En parlant de configuration, après nos deux chapitres sur les fichiers, j'aimerais que vous sauvegardiez les paramètres de configuration de ce petit programme dans un fichier .ini. Je vous laisse également choisir la structure qu'aura ce fichier, les choses que vous allez avoir à y insérer, etc.

Pour le choix des dossiers, je ne vous en avais pas parlé avant, mais un petit module très pratique existe : le FolderBrowserDialog.

Dans la boîte à outils, section boîtes de dialogue. Ce module ouvre une boîte de dialogue, demandant à l'utilisateur de sélectionner un dossier. Il a également la possibilité d'en créer un par la même occasion. Vous pouvez récupérer le dossier sélectionné avec FolderBrowserDialog.SelectedPathFolderBrowserDialogest le nom de votre contrôle.

Pour ce qui est de la liste des dossiers à sauvegarder, vous pouvez les insérer dans une listbox ou une textbox multilignes, au choix.

Pour le reste, je vous laisser agrémenter au choix et selon vos goûts.

Je dois dire que vous avez toutes les compétences et les méthodes de réflexion (savoir trouver les propriétés qui vous seront utiles) requises. Essayez de ne pas vous décourager trop rapidement et de ne pas aller trop vite à la correction.

Eh bien, amis Zéros, au travail !

Correction

Commençons par mon interface (voir figure suivante) et par les fonctionnalités que mon programme contient.

Mon programme ressemble à ça
Mon programme ressemble à ça

Comme vous le voyez, j'ai une listbox qui me permet de lister les répertoires dont je veux la sauvegarde. Vient ensuite un bouton d'ajout et de suppression des répertoires, l'ajout se fait par FolderBrowserDialog, la suppression par lignes sélectionnées dans la listbox. Ensuite, un petit menu de configuration dans lequel on spécifie le dossier où placer les sauvegardes. Lors du clic sur la textbox un FolderBrowserDialog s'ouvre et c'est sa sélection qui remplira la textbox. Après se trouvent des NumericUpDown(un contrôle) permettant de spécifier un nombre avec le clavier ou grâce à des boutons haut et bas. Puis un bouton pour enregistrer la configuration et un second pour effectuer une sauvegarde manuelle.

Je vais vous montrer le code tout de suite, on développera ensuite section par section.

Imports System.IO

Public Class ZBackup

    'Définit les constantes
    Const FichierIni As String = "Zbackup.ini"
    Const LignesFichierIni As Integer = 6
    Const CleSavePath As String = "SavePath"
    Const CleTempSave As String = "TempSave"
    Const CleNbSaves As String = "NbSaves"
    Const ClePaths As String = "Paths"

    Private Sub ZBackup_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        'Configure le timer
        Me.TIM_SAVE.Interval = Me.NUM_SAVETIME.Value * 3600000 'Convertir une heure une milisecondes
        Me.TIM_SAVE.Enabled = True

        'Recupère la configuration enregistrée
        If RecupereInfosFichierIni() Then
            'Effectue d'office une sauvegarde
            Sauvegarde()
        End If

    End Sub

#Region "Interface"

    Private Sub TXT_SAVEPATH_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TXT_SAVEPATH.Click

        'Ajoute la ligne seulement si un dossier a été sélectionné dans le dialogue
        If Me.BD_DOSSIER.ShowDialog() Then
            Me.TXT_SAVEPATH.Text = Me.BD_DOSSIER.SelectedPath
        End If

    End Sub

    Private Sub BT_AJOUT_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BT_AJOUT.Click

        'Ajoute la ligne seulement si un dossier a été sélectionné dans le dialogue
        If Me.BD_DOSSIER.ShowDialog Then
            Me.LB_PATHSASAVE.Items.Add(Me.BD_DOSSIER.SelectedPath)
        End If

    End Sub

    Private Sub BT_SUPPR_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BT_SUPPR.Click

        'Vérifie si une ligne est sélectionnée dans la listbox
        If Not Me.LB_PATHSASAVE.SelectedItem Is Nothing Then
            Me.LB_PATHSASAVE.Items.Remove(Me.LB_PATHSASAVE.SelectedItem)
        Else
            MsgBox("Selectionnez un path à supprimer")
        End If

    End Sub

    Private Sub BT_SAVECFG_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BT_SAVECFG.Click
        SauvegardeFichierIni()
    End Sub

    Private Sub TIM_SAVE_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TIM_SAVE.Tick
        'Sauvegarde avec le timer
        Sauvegarde()
    End Sub

    Private Sub BT_MANUSAVE_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BT_MANUSAVE.Click
        'Sauvegarde manuelle
        Sauvegarde()
    End Sub

#End Region

#Region "FichierIni"

    Sub SauvegardeFichierIni()
        'Vérification sur le path de sauvegarde
        If Me.TXT_SAVEPATH.Text = "" Then
            MsgBox("Veuillez selectionner un path de sauvegarde")
        ElseIf Not Directory.Exists(Me.TXT_SAVEPATH.Text) Then
            MsgBox("Path de sauvegarde invalide")
        Else
            'La fonction recrée le fichier quoi qu'il arrive
            File.WriteAllLines(FichierIni, CreeStructureFichierIni(Me.TXT_SAVEPATH.Text, Me.NUM_SAVETIME.Value, Me.NUM_NBSAVE.Value, Me.LB_PATHSASAVE.Items))
        End If
    End Sub

    Function CreeStructureFichierIni(ByVal SavePath As String, ByVal TempsSave As Integer, ByVal Nbsaves As Integer, ByVal PathsASave As ListBox.ObjectCollection) As String()

        'Crée un tableau du nombre de lignes requises
        Dim FichierIni(LignesFichierIni + PathsASave.Count) As String
        'Remplit la structure du fichier ini
        FichierIni(0) = ";Fichier de configuration du Zbackup"
        FichierIni(1) = "[configuration]"
        FichierIni(2) = CleSavePath & "=" & SavePath
        FichierIni(3) = CleTempSave & "=" & TempsSave
        FichierIni(4) = CleNbSaves & "=" & Nbsaves
        FichierIni(5) = ""
        FichierIni(6) = "[paths]"
        'Remplit dynamiquement les paths souhaités
        Dim Compteur As Integer = LignesFichierIni
        For Each Path As String In PathsASave
            Compteur += 1
            FichierIni(Compteur) = ClePaths & Compteur - LignesFichierIni & "=" & Path
        Next

        Return FichierIni

    End Function

    Function RecupereCleFichierIni(ByVal Cle As String) As String

        For Each Ligne As String In File.ReadAllLines(FichierIni)
            'Découpe la ligne au niveau de « = » (s'il existe), 
            'compare la première partie de la ligne (soit la clé)
            If Ligne.Split("=")(0) = Cle Then
                'Recupère la seconde partie de la ligne (soit la valeur)
                Return Ligne.Split("=")(1)
            End If
        Next
        'Sinon ne retourne rien
        Return ""

    End Function

    Function RecupereInfosFichierIni() As Boolean

        'Vérification de la présence du .ini
        If File.Exists(FichierIni) Then
            'Récuperation
            Dim SavePath As String = RecupereCleFichierIni(CleSavePath)
            Dim TempSAve As String = RecupereCleFichierIni(CleTempSave)
            Dim NbSaves As String = RecupereCleFichierIni(CleNbSaves)
            Dim Paths(100) As String
            Dim i As Integer = 0 '0 car le premier path est à 1 et on incrémente avant
            Do
                i += 1
                Paths(i - 1) = RecupereCleFichierIni(ClePaths & i)
            Loop While Paths(i - 1) <> ""
            'Donc nombre de paths valides : i-1

            'Vérification
            If (SavePath <> "") And (TempSAve <> "") And (NbSaves <> "") And (i - 1 > 0) Then
                'Attribution
                Me.TXT_SAVEPATH.Text = SavePath
                Me.NUM_NBSAVE.Value = NbSaves
                Me.NUM_SAVETIME.Value = TempSAve
                'Nettoie le LB, puis le remplit
                Me.LB_PATHSASAVE.Items.Clear()
                For j As Integer = 0 To i - 1
                    Me.LB_PATHSASAVE.Items.Add(Paths(j))
                Next
            Else
                'Sinon notification
                MsgBox("Le fichier " & FichierIni & " est corrompu, utilisation des paramètres par défaut")
                Return False
            End If
        Else
            'Sinon notification
            MsgBox("Le fichier " & FichierIni & " n'a pas été trouvé, utilisation des paramètres par défaut")
            Return False
        End If

        Return True

    End Function

#End Region

#Region "Sauvegarde"

    Sub Sauvegarde()

        'Vérifie les paramètres
        If Directory.Exists(Me.TXT_SAVEPATH.Text) Then
            'Vérifie le nombre de sauvegardes
            'Supprime la plus vieille si limite atteinte
            NettoieNbSaves()

            'Si le dernier caractère de la chaîne est un « \ », on le supprime
            If Me.TXT_SAVEPATH.Text.EndsWith("\") Then
                Me.TXT_SAVEPATH.Text.Trim("\")
            End If
            'Crée le dossier de sauvegarde avec un nom spécifié
            'Supprime les « / » et « : » de la date et de l'heure
            Dim DossierSave As String = Me.TXT_SAVEPATH.Text & "\Sauvegarde du " & Date.Now.ToShortDateString.Replace("/", "-") & " a " & Date.Now.ToShortTimeString.Replace(":", "-")
            If Not Directory.Exists(DossierSave) Then 's'il existe deux sauvegardes dans la même minute, on ne la fait pas
                Directory.CreateDirectory(DossierSave)
                'Pour chaque path demandé, copie son dossier
                For Each PathASave As String In Me.LB_PATHSASAVE.Items
                    If Directory.Exists(PathASave) Then
                        CopieDossier(New DirectoryInfo(PathASave), New DirectoryInfo(DossierSave & "\" & Path.GetFileName(PathASave)))
                    End If
                Next
            End If
        Else
            MsgBox("Sauvegarde échouée : le path de sauvegarde est invalide, veuillez le redéfinir")
        End If

    End Sub

    Sub NettoieNbSaves()

        Dim Compteur As Integer = 1
        For Each Repertoire As String In Directory.GetDirectories(Me.TXT_SAVEPATH.Text)
            'Si le répertoire est un répertoire de sauvegarde
            If Path.GetFileName(Repertoire).Contains("Sauvegarde") Then
                'Incrémentation du compteur
                Compteur += 1
            End If
        Next

        If Compteur > Me.NUM_NBSAVE.Value Then
            'Détermination du plus ancien
            Dim PlusAncien As DirectoryInfo
            Dim DatePlusAncienne As Date = Date.Now
            For Each Repertoire As String In Directory.GetDirectories(Me.TXT_SAVEPATH.Text)
                'Si le répertoire est un répertoire de sauvegarde
                If Path.GetFileName(Repertoire).Contains("Sauvegarde") Then
                    'Si le répertoire est plus ancien que le précédent
                    If (Directory.GetCreationTime(Repertoire) < DatePlusAncienne) Then
                        'On le place en plus ancien
                        DatePlusAncienne = Directory.GetCreationTime(Repertoire)
                        PlusAncien = New DirectoryInfo(Repertoire)
                    End If
                End If
            Next

            'Supprime le plus vieux
            If PlusAncien.Exists Then
                PlusAncien.Delete(True)
            End If
        End If

    End Sub

    Sub CopieDossier(ByVal DossierSource As DirectoryInfo, ByVal DossierDesination As DirectoryInfo)

        'Crée le dossier
        DossierDesination.Create()

        'Copie les fichiers
        For Each Fichier As FileInfo In DossierSource.GetFiles()
            Fichier.CopyTo(Path.Combine(DossierDesination.FullName, Fichier.Name))
        Next

        'Recommence pour les sous-répertoires
        For Each SousRepertoire As DirectoryInfo In DossierSource.GetDirectories()
            CopieDossier(SousRepertoire, DossierDesination.CreateSubdirectory(SousRepertoire.Name))
        Next

    End Sub

#End Region

End Class

Eh bien, ça devient volumineux !

Comme vous pouvez le voir dès la première ligne, j'ai essayé de rendre le programme « flexible ». Autrement dit, il me suffit de changer les constantes pour changer le nom du fichier ini par exemple, c'est cette constante qui est utilisée à chaque fois qu'une fonction demande le nom de ce fichier.

Trois grandes sections se distinguent :

  • L'interface, contenant la réaction aux boutons, etc.

  • Le fichier ini, contenant tout ce qui touche à la configuration.

  • Finalement, la sauvegarde.

Une rapide vue d'ensemble du fonctionnement :

  • Récupération de la configuration :

    • Si elle n'existe pas, création du fichier ini ;

    • Si elle est corrompue, recréation du fichier ini.

  • À chaque tick de timer (timer configuré sur le temps souhaité entre deux sauvegardes), on effectue la sauvegarde ;

  • Avec le bouton de sauvegarde manuelle, la même action est réalisée ;

  • La sauvegarde consiste à créer un dossier sous la forme Sauvegarde du DD-MM-AAAA a HH-MM ;

  • Puis copie l'intégralité des dossiers en respectant leur arborescence.

L'interface

Voilà donc, commençons par l'analyse la plus simple : celle de l'interface.

Première information : l'ouverture de la FolderBrowserDialog lors du clic sur la textbox.
Eh bien, rien de sorcier, l'événement Click de la textbox !

Private Sub TXT_SAVEPATH_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TXT_SAVEPATH.Click

        'Ajoute la ligne seulement si un dossier a été sélectionné dans le dialogue
        If Me.BD_DOSSIER.ShowDialog() Then
            Me.TXT_SAVEPATH.Text = Me.BD_DOSSIER.SelectedPath
        End If

    End Sub

Lors du clic, on se sert du contrôle BD_DOSSIER qui est mon FolserBrowserDialog. Vu que c'est une boîte de dialogue, c'est la fonction ShowDialog qui est appelée. Puis on récupère la sélection avec la propriété SelectedPath.

Le bouton d'ajout a le même principe, mais il agit sur la listbox, sur le même principe que le treeview que nous avons étudié auparavant ; il faut créer, non plus des Nodes, mais des Items.

Me.LB_PATHSASAVE.Items.Add(Me.BD_DOSSIER.SelectedPath)

C'est dans le membre Items que les fonctions spécifiques à ces objets sont trouvables. La méthode Add() permet d'ajouter un item, avec comme valeur le dossier sélectionné.

Pour la suppression :

'Vérifie si une ligne est sélectionnée dans la listbox
        If Not Me.LB_PATHSASAVE.SelectedItem Is Nothing Then
            Me.LB_PATHSASAVE.Items.Remove(Me.LB_PATHSASAVE.SelectedItem)
        Else
            MsgBox("Selectionnez un path à supprimer")
        End If

Vous vous apercevez qu'une vérification est faite pour voir si une ligne est sélectionnée avec If Not Me.LB_PATHSASAVE.SelectedItem Is Nothing Then . Vous vous apercevez que je n'utilise pas le symbole « <> » pour dire différent, mais not… is nothing. C'est une autre notation plus littérale, tout dépend des goûts de chacun.
Ensuite on supprime avec Items.Remove en passant comme paramètre la ligne sélectionnée.

Pour les autres boutons, la sauvegarde des paramètres appelle la méthode SauvegardeFichierIni(), que nous allons étudier. Le timer et la sauvegarde manuelle appellent la méthode Sauvegarde(), que nous allons aussi étudier.

Sauvegarde en fichier .ini

Attaquons tout de suite la sauvegarde.

Pour ce qui est de cette sauvegarde, je vérifie la présence d'un dossier dans la textbox et si ce dossier est valide. Ensuite j'appelle la fonction File.WriteAllLines(FichierIni, CreeStructureFichierIni(Me.TXT_SAVEPATH.Text, Me.NUM_SAVETIME.Value, Me.NUM_NBSAVE.Value, Me.LB_PATHSASAVE.Items)) qui s'occupe de créer un fichier et d'entrer dedans un tableau de String (une case de tableau pour une ligne).
En premier paramètre, le fichier de destination, c'est notre constante avec le nom du fichier ini. Le second, autrement dit le tableau de String, c'est une fonction que nous allons étudier tout de suite :

Function CreeStructureFichierIni(ByVal SavePath As String, ByVal TempsSave As Integer, ByVal Nbsaves As Integer, ByVal PathsASave As ListBox.ObjectCollection) As String()

        'Crée un tableau du nombre de lignes requises
        Dim FichierIni(LignesFichierIni + PathsASave.Count) As String
        'Remplit la structure du fichier ini
        FichierIni(0) = ";Fichier de configuration du Zbackup"
        FichierIni(1) = "[configuration]"
        FichierIni(2) = CleSavePath & "=" & SavePath
        FichierIni(3) = CleTempSave & "=" & TempsSave
        FichierIni(4) = CleNbSaves & "=" & Nbsaves
        FichierIni(5) = ""
        FichierIni(6) = "[paths]"
        'Remplit dynamiquement les paths souhaités
        Dim Compteur As Integer = LignesFichierIni
        For Each Path As String In PathsASave
            Compteur += 1
            FichierIni(Compteur) = ClePaths & Compteur - LignesFichierIni & "=" & Path
        Next

        Return FichierIni

    End Function

Les valeurs passées en paramètres auraient pu être remplacées par des récupérations directement à l'intérieur de la fonction. Bref, un tableau est créé avec comme taille le nombre de lignes initiales plus le nombre de chemins à insérer. Pour les premières lignes, j'écris manuellement dedans les premières clés. Ce qui nous donne dans le fichier ini une fois créé :

;Fichier de configuration du Zbackup
[configuration]
SavePath=C:\Save
TempSave=1
NbSaves=3

[paths]
Paths1=C:\ASave

Deux sections donc : une configuration, une autre paths.
La section configuration contient le répertoire où sauvegarder, le temps entre deux sauvegardes et le nombre de sauvegardes maximal.
La section paths contient les différents chemins, tous avec un numéro différent. Les techniques peuvent différer, il aurait été possible de mettre tous les chemins sur la même ligne, séparés par des « ; ».

Bref, la création du fichier n'est pas sorcier, le tableau de variables FichierIni() est renvoyé et est écrit dans le fichier.

Maintenant que vous avez vu comment le remplir, voyons comment récupérer les valeurs.

Donc pour cela une petite fonction à laquelle on passe en paramètre la clé à récupérer.

Function RecupereCleFichierIni(ByVal Cle As String) As String

        For Each Ligne As String In File.ReadAllLines(FichierIni)
            'Découpe la ligne au niveau de « = » (s'il existe), 
            'Compare la première partie de la ligne (soit la clé)
            If Ligne.Split("=")(0) = Cle Then
                'Recupère la seconde partie de la ligne (soit la valeur)
                Return Ligne.Split("=")(1)
            End If
        Next
        'Sinon ne retourne rien
        Return ""

    End Function

Principe de cette fonction : on parcourt toutes les lignes du fichier ini, chaque ligne est découpée grâce à la fonction Split().
La fonction Split() s'applique sur une chaîne de caractères, elle permet de « découper » cette chaîne à chaque occurrence du caractère ou de la chaîne passée en argument. Voici un exemple : pour une chaîne de caractères sous la forme Cle1=Valeur1, un Split("=") donnera un tableau de String sous la forme :
Tableau(0) = Cle1
Tableau(1) = Valeur1

Donc un test bête et méchant sur le tableau(0) qui est retourné avec la clé souhaitée nous indique la ligne contenant cette clé. Une fois cette ligne atteinte, le tableau(1), celui contenant la valeur, est retourné.
Si la clé n'est pas trouvée, on retourne "".

Il fallait y penser.

Sauvegarde

Attaquons maintenant le principe de la sauvegarde.

La méthode Sauvegarde() effectue diverses vérifications sur la présence des dossiers, elle crée le dossier dans lequel la sauvegarde va être placée et lance la méthode CopieDossier() que voici :

Sub CopieDossier(ByVal DossierSource As DirectoryInfo, ByVal DossierDesination As DirectoryInfo)

        'Crée le dossier
        DossierDesination.Create()

        'Copie les fichiers
        For Each Fichier As FileInfo In DossierSource.GetFiles()
            Fichier.CopyTo(Path.Combine(DossierDesination.FullName, Fichier.Name))
        Next

        'Recommence pour les sous-répertoires
        For Each SousRepertoire As DirectoryInfo In DossierSource.GetDirectories()
            CopieDossier(SousRepertoire, DossierDesination.CreateSubdirectory(SousRepertoire.Name))
        Next

    End Sub

Cette méthode prend comme arguments des variables de type DirectoryInfo. Ce ne sont pas des variables communes : ce sont des objets. Il faut donc les instancier avec un New.

Lors de l'appel de la ligne avec CopieDossier(New DirectoryInfo(PathASave), New DirectoryInfo(DossierSave & "\" & Path.GetFileName(PathASave))), j'instancie deux objets avec comme paramètres les chemins des dossiers voulus.

Une fois dans la méthode de copie, un dossier est tout d'abord créé, les fichiers contenus y sont copiés également, puis cette action est répétée pour tous ses sous-répertoires. De la même manière que le treeview du chapitre précédent.

Il y a finalement la méthode de nettoyage des sauvegardes (si on ne demande qu'un certain nombre de sauvegardes). Elle parcourt les répertoires créés, récupère la date de création de chacun, identifie le plus vieux et le supprime en utilisant la récursivité de la méthode Directory.Delete.

Eh bien voilà, le code est décortiqué.

Allons un peu plus loin.

Récapitulatif du fichier ini

Bien, procédons à un récapitulatif des fonctions que vous allez pouvoir utiliser dans vos futurs programmes pour créer et gérer un fichier .ini, je ne pense pas revenir dessus par la suite, autant tout résumer tout de suite.

La création

Tout d'abord pour la création du fichier ini.

Deux manières de procéder : la création manuelle en utilisant une fonction du genre :

Function CreeStructureFichierIni(ByVal SavePath As String, ByVal TempsSave As Integer, ByVal Nbsaves As Integer, ByVal PathsASave As ListBox.ObjectCollection) As String()

        'Crée un tableau du nombre de lignes requises
        Dim FichierIni(LignesFichierIni + PathsASave.Count) As String
        'Remplit la structure du fichier ini
        FichierIni(0) = ";Fichier de configuration du Zbackup"
        FichierIni(1) = "[configuration]"
        FichierIni(2) = CleSavePath & "=" & SavePath
        FichierIni(3) = CleTempSave & "=" & TempsSave
        FichierIni(4) = CleNbSaves & "=" & Nbsaves
        FichierIni(5) = ""
        Return FichierIni

    End Function

Cette fonction est appelée manuelle, car vous voyez que chaque ligne doit être écrite côté programmatique.
Très pratique et très visuel pour le programmeur, mais beaucoup moins agréable lorsque vous avez 100 clés de configuration à entrer.

Une autre méthode consiste à passer un tableau à deux dimensions de String, deux colonnes et autant de lignes que de clés.
La première colonne contenant les clés, la seconde les valeurs.

Un rapide algorithme vous construit le même tableau de lignes que vous écrirez dans votre fichier avec WriteAllLines().

Function CreeStructureFichierIni(ByVal ClesValeurs(, ) As String) As String()
		
	Dim Ligne(10) As String
	'Par exemple ClesValeurs a deux dimensions sous la forme : (1, 10)
        'On divise la taille par 2, car elle correspond à l'ensemble des cellules et on a  2 colonnes, donc cellules / 2 = nbligne
	For i As Integer = 0 To te.Length / 2 
            Ligne(i) = ClesValeurs(0,i) & "=" & ClesValeurs(1,i)
        Next

    End Function

Mais ce genre d’algorithme est à faire par vos soins, il n'est pas très compliqué, mais demande un léger travail de recherche.

La récupération de valeurs

Passons tout de suite à la récupération des valeurs.

Ma fonction faite dans ce TP devrait amplement suffir :

Function RecupereCleFichierIni(ByVal Cle As String) As String

        For Each Ligne As String In File.ReadAllLines(FichierIni)
            'Découpe la ligne au niveau de « = »  (s'il existe), 
            'compare la première partie de la ligne (soit la clé)
            If Ligne.Split("=")(0) = Cle Then
                'Recupère la seconde partie de la ligne (soit la valeur)
                Return Ligne.Split("=")(1)
            End If
        Next
        'Sinon ne retourne rien
        Return ""

    End Function

On passe la clé souhaitée en argument, on récupère sa valeur.

Eh bien, je pense que vous avez les éléments en main pour créer les fichiers ini de tous nos prochains TP ! :diable:

Pour aller plus loin

Bon, je ne vais pas continuer l'évolution, car le code me suffit amplement ainsi.

Cette petite idée de TP m'est venue lors d'un après-midi de programmation. J'ai l'habitude de sauvegarder régulièrement mon travail, mais après une fausse manip tout mon projet s'est retrouvé irrécupérable, impossible de faire machine arrière. Ce petit programme effectuant des sauvegardes périodiques du travail aurait pu m'éviter cette erreur.

Bien, passons aux améliorations possibles.

Tout d'abord une sauvegarde plus propre et moins lourde.

Comment faire ?

Eh bien je suppose que vous avez déjà entendu parler de la compression zip. Elle convertit des dossiers et des fichiers en un seul fichier zip. On dit alors que nos fichiers sont compressés sous zip.

Je ne vais pas vous aider plus sur cette voie, car elle est réservée à ceux qui souhaitent effectuer un peu de recherche. Je vais juste vous donner quelques voies.

La première étant l'utilisation du namespace Compressioncontenu dans IO. Assez difficile à utiliser à mon avis, très fastidieux à mettre en place.

La seconde étant l'utilisation de l'utilitaire 7zip, utilitaire open source et gratuit.
Voici sa fiche Clubic : 7zip.

Cet utilitaire dispose d'une interface graphique, mais aussi d'une utilisation en lignes de commande.

Les commandes (arguments) possibles avec l'exécutable 7z.exe sont visibles à la figure suivante.

Les commandes possibles avec l'exécutable 7z.exe
Les commandes possibles avec l'exécutable 7z.exe

Cette manipulation est réservée aux plus expérimentés d'entre vous, il va falloir combiner commandes et chemins de fichiers dans une fonction VB nommée Shell() permettant l'éxécution de programmes shell.

Exemple : si votre 7z.exe est dans le dossier de votre programme, il faudra utiliser Shell("7z.exe a MonArchive.zip MonFichierAZipper").

Je vous laisse explorer cette voie qui semble prometteuse.

Reste ensuite comme améliorations possibles un écran supplémentaire listant les sauvegardes effectuées et la possibilité de restaurer l'une d'entre elle.

Également : une exécution de ce programme en arrière-plan, voire en tant que service.

Pour l'arrière-plan, il faudra déjà s'employer à rendre la forme principale à Visible = false.
Puis créer une icône contextuelle, un contrôle tout fait existe, cherchez dans votre boîte à outils.
Puis récupérer l'événement correspondant au clic ou au double-clic sur cette icône pour faire repasser votre forme à Visible = true.

Finalement le lancement au démarrage : il faut créer un raccourci de votre programme ou placer votre programme dans le dossier
C:\Users\@VOTREUSER@\AppData\Roaming\Microsoft\Windows\Start Menu\Programs.

Que d'améliorations possibles ! En y passant un peu de temps votre programme peut devenir une véritable sauvegarde périodique de vos données vitales, tout en restant discret et rapide. Et puis lors de notre partie concernant le réseau, une sauvegarde sur un FTP ou un serveur sera envisageable.

Voilà amis Zéros, bonne chance !

Exemple de certificat de réussite
Exemple de certificat de réussite