• 20 heures
  • Facile

Ce cours est visible gratuitement en ligne.

Ce cours existe en livre papier.

Vous pouvez être accompagné et mentoré par un professeur particulier par visioconférence sur ce cours.

J'ai tout compris !

Mis à jour le 20/12/2017

Les fichiers - partie 2/2

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Prêts à acquérir encore plus de notions sur les fichiers ?
Nous allons voir plus de fonctions sur les fichiers, puis nous aborderons les répertoires !
Vous aurez bientôt les clés en main pour interagir avec tout votre système de fichiers.
C'est parti !

Plus loin avec nos fichiers

La technique que je vous ai montrée utilise le principe du stream. Autrement dit, du flux. Dans le principe : le fichier est intégralement ouvert et inséré dans un objet de type Stream. Pendant le temps que le stream est ouvert (fichier ouvert par le programme), son écriture par une autre instance (un autre programme) est impossible.

Cette technique comporte des avantages et des inconvénients : on peut être certain que le fichier ne sera pas modifié pendant le déroulement du programme, mais par contre il est bloqué et donc plusieurs programmes ne peuvent pas travailler dessus en même temps.

Bref, je parie que vous voulez une autre technique.

La classe File vient à votre secours !

La classe File

Cette classe est préimplémentée dans le framework. On va créer le même programme de lecture/écriture que précédemment avec cette classe. La même interface donc, mais le code va légèrement changer :

Imports System.IO

Public Class Form1

    Const PATHFICHIER As String = "Zero.txt"    

    Private Sub BT_CLEARLIRE_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BT_CLEARLIRE.Click
        Me.TXT_LECTURE.Text = ""
    End Sub

    Private Sub BT_CLEARECRIRE_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BT_CLEARECRIRE.Click
        Me.TXT_ECRITURE.Text = ""
    End Sub

    Private Sub BT_CLEAR_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BT_CLEAR.Click
        File.WriteAllText(PATHFICHIER , "")
    End Sub

    Private Sub BT_LIRE_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BT_LIRE.Click
        Me.TXT_LECTURE.Text = File.ReadAllText(PATHFICHIER)
    End Sub

    Private Sub BT_ECRIRE_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BT_ECRIRE.Click
        If Me.CHK_DEBUT.Checked Then
	    'Depuis le début
            File.WriteAllText(PATHFICHIER , Me.TXT_ECRITURE.Text)
        Else
	    'À la suite
            File.AppendAllText(PATHFICHIER , Me.TXT_ECRITURE.Text)
        End If

    End Sub
End Class

Il n'y a plus rien !?!

Eh bien oui, si on veut. La classe File a les outils nécessaires pour effectuer les actions dont nous avions besoin.

Mais tu es stupide ! Pourquoi nous as-tu ennuyés avec tes 500 lignes au chapitre précédent ?

Eh bien, je vous aurais montré qu'on aurait pu le faire ainsi, auriez-vous réellement pris le temps de comprendre tout ce qui a été introduit au chapitre précédent ? (Les objets, le stream, les conversions de caractères).

Bon, cette classe nous permet de lire/écrire rapidement dans nos fichiers. Examinons quand même ces lignes.

Tout d'abord la déclaration d'une variable constante pour spécifier le Path que je vais utiliser pendant tout le programme : Const PATHFICHIER As String = "Zero.txt". Path relatif bien évidemment.

File.WriteAllText(PATHFICHIER , Me.TXT_ECRITURE.Text) : la méthode WriteAllText de la classe File permet d'écrire du texte dans un fichier en redémarrant du début. Donc effacement du contenu précédent (ce que j'ai utilisé pour l'effacement du fichier).

File.AppendAllText(PATHFICHIER , Me.TXT_ECRITURE.Text) : la méthode AppendAllText, quant à elle, écrit à la suite du fichier, donc je l'ai utilisée lorsque la checkbox est cochée.

Il nous reste finalement la lecture : Me.TXT_LECTURE.Text = File.ReadAllText(PATHFICHIER). Une fonction qui cette fois-ci lit depuis le début et entre le tout dans un String, que j'affiche directement via ma textbox.

Quelle simplification quand même ! Je vous rassure, par la suite nous utiliserons cette classe, nous nous concentrerons plus sur le fonctionnel des fichiers que sur comment effectuer nos manipulations dessus.

Découvrons d'autres manipulations

Bien, tout d'abord le légendaire Move, autrement dit le déplacement du fichier.

File.Move(Source as string, Destination as string)

Vous pouvez bien évidemment utiliser des chemins relatifs, absolus, ou mélanger les deux. :D
Cette méthode est également utilisée pour renommer les fichiers, il suffit simplement d'effectuer le Move avec deux noms différents, mais sur le même Path.

La copie
File.Copy(Source as string, Destination as string)

Même principe que la méthode précédente, vous n'avez cependant pas le droit d'attribuer le même nom à la source et à la destination.

La vérification de la présence du fichier
File.Exists(Fichier as string)

Fonction très importante ! Lorsque l'on va effectuer des manipulations, toujours vérifier la présence du fichier avant d'effectuer une action dessus ! Vous ne voulez pas vous retrouver avec une grosse erreur qui tache ! Renvoie un Boolean : True si présence du fichier, False dans le cas contraire.

Les répertoires

Cette fois, pas de stream ou autres, la classe Directory est la seule dans le namespace IO (directory : répertoire).

Fonctions de modification

On va commencer par la fonction à utiliser avant toute chose :

La vérification
Directory.Exists(Path As String)

Renvoie un booléen encore une fois, bien évidemment très important ! On l'utilisera systématiquement !

La création de dossiers
Directory.CreateDirectory(Path As String)

Alors, cette méthode est assez magique. Elle va créer entièrement le Path spécifié. Je m'explique.
Parlons en chemin relatif : il n'y a actuellement aucun dossier dans le répertoire d'exécution de votre programme. Si en argument de la méthode je passe Dossier1/SousDossier1/SousSousDossier1, il y aura trois dossiers de créés, suivant l'arborescence suivante : le dossier Dossier1 sera créé directement dans le répertoire, le dossier SousDossier1 sera créé dans Dossier1, et finalement le dossier SousSousDossier1 sera créé dans SousDossier1. Le tout pour dire à quel point cette méthode peut se révéler pratique.

La suppression
Directory.Delete(Path As String, Recursif As Boolean)

Alors, ici nous avons un second argument en plus du chemin du dossier à supprimer ; il correspond à la récursivité. Si vous activez la récursivité, les dossiers et fichiers « en dessous » (dans l'arborescence des fichiers) du chemin que vous avez indiqué seront également supprimés ; sinon, si la récursivité n'est pas activée et que vous tentez de supprimer un dossier qui n'est pas vide, une erreur surviendra.
En résumé : la récursivité supprime le répertoire plus l'intégralité de son contenu !

Le légendaire Move
Directory.Move(PathSource As String, PathDest As String)

Même principe que pour les fichiers, avec les répertoires cette fois-ci : déplace le dossier et son contenu vers le nouveau Path.

Fonctions d'exploration

Bien, vous savez maintenant manipuler les fichiers et les répertoires, mais il va falloir associer les deux pour pouvoir rendre vos programmes exportables et adaptables aux environnements.

Nous allons donc apprendre à chercher dans un dossier spécifié les sous-dossiers et les fichiers qu'il contient.
Bref, cela va nous permettre de pouvoir nous représenter notre arborescence. Nous allons également créer un petit programme permettant de représenter l'arborescence de notre disque.

Commençons donc avec les fonctions.

Rechercher tous les dossiers contenus dans le dossier spécifié
Directory.GetDirectories(Path as String)

Renvoie un tableau de string contenant le Path de tous les dossiers qui sont contenus dans le dossier spécifié.

Rechercher tous les fichiers contenus dans un dossier spécifié
Directory.GetFiles(Path as String)

Comme pour au-dessus, même remarque, le Path renvoyé correspond à celui que vous avez passé en argument. Renvoie les fichiers avec leur extension.

Un rapide bout de code permet de lister les fichiers présents en utilisant cette fonction :

For Each Fichier As String In Directory.GetFiles("c:/")
            MsgBox(Fichier)
        Next

Mini-TP : lister notre arborescence

Tout d'abord, explorons notre arborescence avec une commande toute faite dans notre invite de commande Windows. La commande shell (commande spécifique à Windows) s'appelle Tree. Elle donne un résultat similaire à la figure suivante.

Résultat de la commande shell
Résultat de la commande shell

Vous n'avez pas besoin d'utiliser cette commande, c'est pour vous montrer l'arborescence du dossier dans lequel nous allons faire notre mini-TP.

Nous allons donc retrouver notre arborescence de manière à se retrouver avec le même schéma, le tout grâce à un algorithme.
Je vous ai déjà parlé du principe d'un algorithme. Eh bien, nous allons devoir en trouver un pour pouvoir effectuer ce listage.
Nous récupérerons les informations et les afficherons dans un TreeView (ça vous donnera l'occasion de découvrir un nouveau contrôle), spécifiquement conçu pour effectuer des arborescences (avec des parents et des enfants).

Pour résumer, dans le TreeView : un dossier correspondra à un nœud principal (on peut cliquer dessus pour le « déplier »), et un fichier sera un nœud simple, pas de possibilité de le « déplier ».

C'est un programme très basique, sa base pourra être utilisée dans d'autres programmes qui nécessitent une exploration des répertoires.

Donc, passons à l'algorithme. Je ne suis pas là pour vous apprendre les rudiments et normes de l'algorithmie, j'aimerais juste un peu de logique de votre part, peu importe comment vous vous représentez ce qu'il va y avoir à faire (schéma, texte, dessin…).

Le tout est de comprendre ce qu'on va devoir effectuer comme action et appeler comme fonctions.

Un algorithme version texte tout simple

Parcourir le répertoire, pour chaque dossier ajouter un nœud principal, pour chaque fichier ajouter un nœud simple.
Répéter cette action pour chaque répertoire

(Attention, cet algorithme ne respecte pas les normes de l'algorithmie, si vous voulez en savoir plus, de très bon tutos existent sur le SdZ.)

Maintenant il va falloir l'adapter pour le rentrer dans notre code.

Imports System.IO

Public Class Form1

    Const RepertoireALister As String = "."

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Définit le premier nœud
        Me.TV_ARBORESCENCE.TopNode = Me.TV_ARBORESCENCE.Nodes.Add(RepertoireALister, RepertoireALister)

        'Arborescence du premier nœud
        For Each Repertoire As String In Directory.GetDirectories(RepertoireALister)
            Me.TV_ARBORESCENCE.TopNode.Nodes.Add(Repertoire, Path.GetFileName(Repertoire))
            'Récursif
            ListeArborescenceDossier(Repertoire, Me.TV_ARBORESCENCE.TopNode)
        Next
        'Fichiers du premier nœud
        For Each Fichier As String In Directory.GetFiles(RepertoireALister)
            Me.TV_ARBORESCENCE.TopNode.Nodes.Add(Path.GetFileName(Fichier))
        Next
    End Sub

    Sub ListeArborescenceDossier(ByVal RepertoireActuel As String, ByVal NodeActuel As TreeNode)
        'Recupère le node dans lequel on est
        Dim Node As TreeNode = NodeActuel.Nodes(RepertoireActuel)
        'Répertoires de ce nœud
        For Each Repertoire As String In Directory.GetDirectories(RepertoireActuel)
            Node.Nodes.Add(Repertoire, Path.GetFileName(Repertoire))
            'Récursif
            ListeArborescenceDossier(Repertoire, Node)
        Next
        'Fichiers de ce nœud
        For Each Fichier As String In Directory.GetFiles(RepertoireActuel)
            Node.Nodes.Add(Path.GetFileName(Fichier))
        Next
    End Sub

End Class

Expliquons un peu le tout. Tout d'abord « node » en anglais signifie « nœud ».
Le répertoire que je dois explorer en constante, vous pouviez bien évidemment créer une textbox demandant à l'utilisateur quel dossier lister. Le Path que j'ai utilisé est « . », cela signifie le dossier courant, c'est un Path relatif.

Vient le Load, je crée d'office un TopNode, autrement dit « le nœud le plus haut », le nœud principal de notre Treeview. J'en profite pour créer un nœud avec : Me.TV_ARBORESCENCE.Nodes.Add(). En premier argument de cette fonction, la « clé » pour identifier le nœud dans le Treeview (cette clé doit avoir un nom unique), et en second le texte qui sera affiché sur mon nœud.

Ensuite, la petite boucle que je vous ai montrée plus haut : je parcours tous les répertoires dans le répertoire à lister, j'ajoute chacun en tant que nœud principal avec comme clé leur Path entier (exemple : ./Dossier1/SousDossier1) donc un nom qui est unique, et en texte le nom du dossier simplement. Nom de dossier que j'ai récupéré en utilisant la classe Path qui donne des méthodes et fonctions pour manipuler les chemins. J'ai utilisé la fonction GetFileName qui renvoie le nom du fichier ou le nom d'un dossier contenu dans un Path.

Puis j'appelle une méthode que je vous exposerai juste après.

Quand il n'y a plus de dossiers on passe aux fichiers, sur le même principe sauf que ces nœuds n'auront pas de nœuds enfants, donc ne seront pas dépliables.

La méthode que j'ai mise juste après, eh bien c'est elle qui va nous permettre d'effectuer la récursivité de notre algorithme à travers tous les sous-dossiers.

Sans elle, on aurait seulement le niveau 0 de notre arborescence de listé (les dossiers et fichiers du répertoire principal) et pas plus loin.

Eh bien, pour ce qui est de la fonction, elle effectue exactement la même chose que ce que je viens d'expliquer, mais où le nom du répertoire et le nœud dans lequel on se trouve actuellement sont passés en paramètres de façon à permettre de la rappeler dynamiquement et pour qu'elle puisse s'adapter aux différents niveaux de l'arborescence.

Et voici le résultat à la figure suivante.

Le résultat final
Le résultat final

Je tiens juste à vous conseiller d'essayer de comprendre le fonctionnement de ce programme étape par étape (commencez par un seul niveau d'arborescence), vous allez comprendre la démarche qu'il effectue et ce sera un premier et grand pas vers des notions de programmation plus complexes que nous allons aborder dans la partie 3 de ce tutoriel.

Autre conseil pour vous éclaircir le programme : créez des variables intermédiaires dans lesquelles vous vous habituerez à trouver le bon type de variable à employer, les méthodes disponibles sur ce type, pour finalement arriver à tout rassembler, tout en le laissant clair à vos yeux.

Un fichier bien formaté

Bien, passons aux fichiers de configuration. Peut-être que certains d'entre vous ont déjà vu les fichiers de configuration standard de Windows : les fichiers .ini. Ils ont été utilisés par Windows pour définir les paramètres de configuration. Ce sont de simples fichiers contenant du texte, mais au lieu d'avoir l'extension basique de texte .txt, ils ont une extension .ini.

Petite parenthèse sur les extensions : elles ne définissent pas obligatoirement le contenu du fichier, les fichiers .jpg contiennent habituellement des images et ont l'habitude d'être ouverts par des logiciels de dessin ou de visualisation d'images, mais ils peuvent très bien contenir du texte et être ouverts avec le bloc-notes.

Les fichiers .ini contiennent donc du texte, mais formaté d'une certaine manière ; nous allons étudier ce formatage ici.

Exemple de mon fichier Win.ini
; for 16-bit app support
[fonts]
[extensions]
[mci extensions]
[files]
[Mail]
MAPI=1
[MCI Extensions.BAK]
3g2=MPEGVideo
3gp=MPEGVideo
3gp2=MPEGVideo
3gpp=MPEGVideo
aac=MPEGVideo
adt=MPEGVideo
adts=MPEGVideo
m2t=MPEGVideo
m2ts=MPEGVideo
m2v=MPEGVideo
m4a=MPEGVideo
m4v=MPEGVideo
mod=MPEGVideo
mov=MPEGVideo
mp4=MPEGVideo
mp4v=MPEGVideo
mts=MPEGVideo
ts=MPEGVideo
tts=MPEGVideo
Explications

Le contenu d'un fichier de configuration .ini contient trois types de lignes :

  • Les lignes commençant par « ; » sont des commentaires, elles ne sont pas prises en compte pendant le traitement du fichier.

  • Les lignes où il y a des crochets : « [ » et « ] » définissent une nouvelle section. Cela permet d'organiser un minimum notre fichier .ini.

  • Finalement les lignes de clé, les plus importantes, elles contiennent les variables que nous stockons. Par exemple MAPI=1 signifie que la variable (ou clé) MAPI est égale à 1.

Bon, vous voyez maintenant le principe d'un fichier de configuration. À quoi diable va-t-il nous servir ? Eh bien simplement à garder des paramètres du programme même s'il y a eu un arrêt de ce dernier.

Bien, vous voilà donc avec une petite norme à respecter pour stocker vos informations de configuration (ça ne fait pas de mal de temps en temps).

Nous allons passer à un TP conséquent et qui va vous demander de réviser vos notions sur les fichiers. C'est juste après.

  • File et Directory sont des objets destinés à contenir respectivement des fichiers et des répertoires.

  • Vous pouvez récupérer les fichiers d'un répertoire par la commande Directory.GetFiles().

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