|
Site |
Cours VB.net |
|
|
|
Les fichiers. |
|
|
Comment lire et écrire dans des fichiers du texte, des octets, du XML du Rtf ?
Les Classes du Framework
FileOpen
Les objets
Les nouveautés de VS 2005
Comment ouvrir une boite de dialogue pour choisir un fichier?
Un exemple de classe permettant d'enregistrer une variable structurée avec des FileStream.
Généralités et rappels:
Le mot 'fichier' est a prendre au sens informatique: ce n'est pas un ensemble de fiches mais plutôt un ensemble d'octets. Un fichier peut être un programme (Extension .EXE), du texte (Extension .TXT ou .DOC....), une image (Extension .BMP .GIF .JPG...), une base de données (.MDB..) du son, de la vidéo....
Pour travailler avec du texte, des octets, des données très simple (sans nécessité d'index, de classement..), on utilise les méthodes décrites dans cette page: travail direct dans les fichiers séquentiels, aléatoires, binaires. Mais dès que les informations sont plus structurées, il faut utiliser les bases de données (Il y a plusieurs chapitre plus loin traitant des bases de données).
Un fichier a un nom: 'Image.GIF' , une extension: '.GIF' qui en indique généralement le type de contenu , des attributs (Longueur, Date de création, de modification, Fichier en lecture seule ou non..).
On voit cela dans l'explorer Windows:

Un fichier est composé d'enregistrements qui sont des 'paquets' de données; suivant le type de fichier un enregistrement peut correspondre à une ligne, un octet, un groupe d'octets..
Un fichier peut être vu comme contenant du texte, de l'XML, des octets.
Comment utiliser les fichiers? Voici le plan de cet article:
A- Il est conseillé de travailler avec les Classes du Frameworks
Avec la Classe FileInfo, on obtient des renseignements sur le fichier.
Pour lire écrire dans un fichier (en dehors des bases de données), il y a plusieurs méthodes:
Avec la Classe System.Io on a a notre disposition StreamReader StreamWriter BinaryReader BinaryWriter FileStream:
Pour lire ou écrire dans un fichier, il faut l'ouvrir (Open), lire ou écrire en utilisant un flux de données (Stream) puis le refermer (Close).
Le Stream (flux, torrent, courant) est une notion générale, c'est donc un flux de données provenant ou allant vers un fichier, un port, une connexion TCP/IP...
L'accès est séquentiel: les données sont traitées du début à la fin du fichier.
B- Il existe toujours la méthode classique du FileOpen:
On ouvre le fichier en mode séquentiel, aléatoire, binaire, on lit X enregistrements, on referme le fichier.
C- Avec certains objets, on gèrent automatiquement les lectures écritures sur disque.
Comme avec le RichTextBox par exemple.
En résumé, pour travailler sur les fichiers, on dispose:
Les 2 derniers font appel au premier; donc pourquoi ne pas utiliser directement les Classe .NET?
A- Classe FileInfo et File, Stream.
Pour travailler sur les fichiers, il faut au préalable taper:
Imports
System.IOLa classe File est utilisée pour travailler sur un ensemble de fichier ou un fichier (sans instanciation préalable: ce sont des méthodes statiques), la Classe FileInfo donne des renseignements sur un fichier particulier (Il faut instancier au préalable un objet FileInfo).
La Classe File possède les méthodes suivantes.
Exists Teste si le fichier existe.
Create Crée le fichier
Copy Copie le fichier
Delete Efface le fichier
GetAttributes , SetAttributes Lire ou écrire les attributs.
GetCreationTime , GetLastAccessTime , GetLastWriteTime et les Set.. correspondant.
Move Déplacement de fichier
Replace Framework 2
ReadAllText, WriteAllText Framework 2 lire ou écrire un texte dans un fichier
ReadAllLines, WriteAllLines Framework 2 lire ou écrire des lignes dans un fichier
ReadAllBytes, WriteAllBytes Framework 2 lire ou écrire des octets dans un fichier
Toutes les méthodes Open (pour un FileStream) OpenRead, OpenWrite, OpenText.
Exemple:
Un fichier existe-t-il? Afficher True s'il existe:
Label1.Text = File.Exists("vessaggi.gif").ToString
Exists est bien une 'méthode de Classe': pas besoin d'instancier quoi que ce soit.
Déplacer un fichier de c: vers d:?
File.Move("c:\monText.txt", "d:\monText.txt")
Copier un fichier de c: vers d:?
File.Copy("c:\monText.txt", "d:\monText.txt", True)
Le dernier argument facultatif (framework 2) permet de remplacer cible s'il existe.
Sauvegarde un fichier et le remplace? (Framework 2)
File.Copy("c:\monText.txt", "c:\newText.txt",, "c:\newText.bak " True)
Sauvegarde monText.tx sans un .bak , puis copie NewText.txt dans monText.tx ; True permet de remplacer cible s'il existe.
Efface un fichier:
File.Delete("d:\monText.txt")
Lire la totalité d'un fichier texte? (Framework 2)
Dim myText As String =File.ReadAllText("c:\monText.txt")
File.WriteAllText("c:\monText.txt", myText)
'pour réecrire le texte dans un autre fichier.La méthode AppendAllText existe aussi.
Lire et mettre dans un tableau les lignes d'un fichier texte? (Framework 2)
Dim myLines() As String =File.ReadAllLines("c:\monText.txt")
Lire et mettre dans un tableau les octets d'un fichier? (Framework 2)
Dim myBytes() As Byte =File.ReadAllBytes("c:\monText.txt")
Un fichier est-il en lecture seule?
If File.GetAttributes("c:\monText.txt") And FileAttributes.ReadOnly Then..
La Classe FileInfo possède les propriétés suivantes.
Name Nom du fichier (sans chemin)
FullName Nom complet avec chemin
Extension Extension (.txt par exemple)
Length Longueur du fichier.
Directory Répertoire parent
DirectoryName Répertoire ou se trouve le fichier
Exists Existe?
LastAccessTime Date du dernier accès, LastWriteTime existe aussi.
Attributes Attributs
Il faut faire un AND entre Attributes et une valeur de l'énumération FileAttributes ( Archive, Compressed, Directory, Encrypted, Hidden, Normal, ReadOnly, System, Temporaly).
Pour tester ReadOnly par exemple:
Dim sNom As String = "c:\monfichier.txt"
Dim Fi As FileInfo 'On déclare un FileInfo
Fi=New FileInfo( sNom) 'On instancie ce FileInfo avec comme paramètre le nom du fichier
Fi.Attributes And FileAttributes.ReadOnly Retourne True si le fichier est ReadOnly
Et aussi:
Fi.Name retourne "monfichier.txt"
Fi.FullName retourne "c:\monfichier.txt"
Fi.Name.Substring(0, Fi.Name.LastIndexOf(".")) retourne "monfichier" : pas de chemin ni d'extension.
Et les méthodes suivantes:
Create, Delete, MoveTo
AppendTex, CopyTo Open, OpenRead, OpenWrite, OpenText..
On voit que toutes les informations sont accessibles.
Exemple:
Pour un fichier, afficher successivement le nom, le nom avec répertoire, le répertoire, la longueur, la date de dernière écriture et si le fichier est en ReadOnly.
Dim sNom As String = "c:\monfichier.txt"
Dim Fi As FileInfo 'On déclare un FileInfo
Fi=New FileInfo( sNom) 'on instance ce FileInfo avec comme paramètre le nom du fichier
MsgBox("Nom="& Fi.Name)
MsgBox("Nom complet ="& Fi.FullName)
MsgBox("Répertoire="& Fi.DirectoryName)
MsgBox("Longueur="& Fi.Length.ToString)
MsgBox("Date der modification="& Fi.LastWriteTime.ToShortDateString)
MsgBox("ReadOnly="& (Fi.Attributes And FileAttributes.ReadOnly).ToString)
Classe My.Computer.FileSystem en VS 2005.
En VS 2005 il y a en plus la classe My.Computer.FileSystem qui simplifie énormément les choses:
les méthodes CopyFile, DeleteFile, FileExits permettent de copier, effacer un fichier ou de voir s'il existe. Il existe aussi RenameFile et MoveFile.
Exemple :
Afficher dans une MsgBox True si 'c:\config.sys' existe.
MsgBox(
My.Computer.FileSystem.FileExists("c:\config.sys").ToString)Exemple :
Afficher la liste des fichiers qui sont sous c:\; ici on utilise GetFiles qui retourne une collection des fichiers.(count contient le nombre de fichiers, item () les noms.
Dim
i As Integer For i = 0 To My.Computer.FileSystem.Getfiles("c:\").Count - 1ListBox1.Items.Add(
My.Computer.FileSystem.GetFiles("c:\").Item(i)) Next iUn fichier existe t-il et est-il ouvert et utilisé par une autre application?
If My.Computer.FileSystem.FileExists("c:\monText.txt") Then
Try'on tente d'ouvrir un stream sur le fichier, s'il est déjà utilisé, cela déclenche une erreur.
Dim fs As IO.FileStream = My.Computer.FileSystem.GetFileInfo("c:\monText.txt").Open(IO.FileMode.Open, IO.FileAccess.Read)fs.Close()
Catch ex As ExceptionMsgBox(
"Le fichier est déjà ouvert") End Try End If
Utiliser les "Stream".
Le Stream (flux, torrent, courant) est une notion générale, c'est donc un flux de données provenant ou allant vers un fichier, un port, une connexion TCP/IP...
Ici on utilise un Stream pour lire ou écrire dans un fichier.
L'accès est séquentiel: les données sont traitées du début à la fin du fichier.
Pour écrire dans un fichier texte:
Il faut instancer un objet de la classe StreamWriter . On écrit avec Write ou WriteLine.(ajoute un saut de ligne) Enfin on ferme avec Close.
On peut instancier avec le constructeur de la classe StreamWriter et avec New, ou par la Classe File.
Dim SW As New StreamWriter ("MonFichier.txt") ' crée ou si existe écrase
Il existe une surcharge permettant de ne pas écraser mais d'ajouter à la fin du fichier:
Dim SW As New StreamWriter ("MonFichier.txt", True) ' crée ou si existe ajoute
Avec la classe File:
Dim SW As StreamWriter=File.CreateText ("MonFichier.txt") ' crée ou si existe écrase
Dim SW As StreamWriter = File.AppendText("MonFichier.txt") ' crée ou si existe ajoute
Ensuite pour écrire 2 lignes:
SW.WriteLine ("Bonjour")
SW.WriteLine ("Monsieur")
Enfin on ferme:
SW.Close()
Pour lire dans un fichier Texte:
Il faut instancier un objet de la classe StreamReader. On lit avec Read (un nombre d'octet) ReadLine (une ligne) ReadToEnd (de la position courante jusqu'à la fin). Enfin on ferme avec Close.
Avec le constructeur de la Classe Stream Reader:
Dim SR As New StreamReader ("MonFichier.txt")
Avec la Classe File:
Dim SR As StreamReader=File.OpenText ("MonFichier.txt") '
Comment lire chaque ligne du fichier et s'arrêter à la fin?
En effet on ne sait pas habituellement combien le fichier contient de ligne, si le fichier contient 2 lignes il faut en lire 2 et s'arrêter sinon on tente de lire après la fin du fichier et cela déclenche une erreur.
3 solutions:
1-Utiliser ReadToEnd qui lit en bloc jusqu'à la fin.
2-Avant ReadLine mettre un Try: quand l'erreur 'fin de fichier' survient elle est interceptée par Catch qui sort du cycle de lecture et ferme le fichier.
3-Utiliser Peek qui lit dans le fichier un caractère mais sans modifier la position courante de lecture.
La particularité de Peek est de retourner -1 s'il n'y a plus de caractère à lire sans déclencher d'erreur, d'exception.
La troisième solution est la plus générale et la plus élégante:
Do Until SR.Peek=-1
Ligne=SR.ReadLine()
Loop
Enfin on ferme:
SR.Close()
Notion de 'Buffer', utilisation de Flush.
En fait quand on écrit des informations sur le disque, le logiciel travaille sur un buffer ou mémoire tampon qui est en mémoire vive. Si on écrit des lignes dans le fichier, elles sont 'écrites' dans le buffer en mémoire vive. Quand le buffer est plein,(ou que l'on ferme le fichier) l'enregistrement du contenu du buffer est effectué effectivement sur le disque.
Ce procédé est général à l'écriture et à la lecture de fichier mais totalement transparent car le programmeur ne se préoccupe pas des buffers.
Parfois, par contre, même si on a enregistré peu d'information, on veut être sûr qu'elle est sur le disque, il faut donc forcer l'enregistrement sur disque même si le buffer n'est pas plein, on utilise alors la méthode Flush.
SW.Flush()
Le fait de fermer un fichier par Close, appelle automatiquement Flush() ce qui enregistre des données du buffer.
B- Utiliser "FileOpen".
Visual Basic fournit trois types d'accès au fichier :
Philippe
Jean-François
Louis On ne peut qu'écrire le premier enregistrement puis le second, le troisième, le quatrième...
Pour lire c'est pareil: on ouvre , on lit le premier, le second, le troisième, le quatrième....
Pour lire le troisième enregistrement , il faut lire avant les 2 premiers.
Philippe
1 place de la gare
Jean
35 rue du cloître
Pierre
14 impasse du musée
Louis
sdf
Les enregistrements ont une longueur fixe: il faut prévoir!! si on décide de 20 caractères pour le prénom, on ne pourra pas en mettre 21, le 21ème sera tronqué, à l'inverse l'enregistrement de 15 caractères sera complété par des blancs.
Il n'y a pas de séparateur entre les enregistrements.
Les enregistrements peuvent être constitués d'un ensemble de variables: une structure, ici prénom et adresse.
Ensuite on peut lire directement n'importe quel enregistrement,le second enregistrement par exemple, ou écrire sur le 3éme.(on comprend que, connaissant la longueur d'un enregistrement qui est fixe, l'ordinateur peut calculer la position d'un enregistrement quelconque.)
En pratique:
Les fichiers séquentiels sont bien pratique pour charger une série de ligne, (toujours la même) dans une ListBox par exemple.
Faut-il utiliser les fichiers séquentiels ou random (à accès aléatoire, à accès direct) pour créer par exemple un petit carnet d'adresse?
Il y a 2 manières de faire:
Si on ouvre un fichier en écriture et qu'il n'existe pas sur le disque, il est crée.
Si on ouvre un fichier en lecture et qu'il n'existe pas, une exception est déclenchée (une erreur). On utilisait cela pour voir si un fichier existait: on l'ouvrait, s'il n'y avait pas d'erreur c'est qu'il existait. Mais maintenant il y a plus simple pour voir si un fichier existe (File.Exists).
Si on ouvre un fichier et que celui-ci est déjà ouvert par un autre programme, il se déclenche généralement une erreur (sauf si on l'ouvre en Binaire, c'était le cas en VB6, c'est à vérifier en VB.NET).
Pour ouvrir un fichier on utilise FileOpen
FileOpen (FileNumber, FileName, Mode, Access, Share, RecordLength)
Pour écrire dans un fichier on utilise
Print , Write, WriteLine. dans les fichiers séquentiels
FilePut dans les fichiers aléatoires
Pour lire dans un fichier on utilise:
Input, LineInput dans les fichiers séquentiels
FileGet dans les fichiers aléatoires.
Pour fermer le fichier on utilise FileClose()
Numéro de fichier:
Pour repérer chaque fichier, on lui donne un numéro unique (de type Integer).
La fonction FreeFile retourne le premier numéro libre.
Dim No as Integer
No= Freefile()
Ensuite on peut utiliser No pour repérer le fichier sur lequel on travaille.
FileOpen( No, "MonFichier", OpenMode.Output)
Print(No,"toto")
FileClose (No)
Fichier séquentiel:
Vous devez spécifier si vous voulez lire (entrer) des caractères issus du fichier (mode Input), écrire (sortir) des caractères vers le fichier (mode Output) ou ajouter des caractères au fichier (mode Append).
Ouvrir le fichier 'MonFichier' en mode séquentiel pour y écrire:
Dim No as integer
No= Freefile
FileOpen( No, "MonFichier", OpenMode.Output)
Pour écrire dans le fichier séquentiel: on utilise Write ou WriteLine Print ou PrintLine:
La fonction Print écrit dans le fichier sans aucun caractère de séparation.
Print(1,"toto")
Print(1,"tata")
Print(1, 1.2)
Donne le fichier 'tototata1.2'
La fonction Write insère des points-virgules entre les éléments et des guillemets de part et d'autre des chaînes au moment de leur écriture dans le fichier, les valeurs booléens et les variables DateTime sont écrites sans problèmes.
Write(1,"toto")
Write(1,"tata")
Write(1, 1.2)
Donne le fichier '"toto";"tata";1.2"
Attention s'il y a des points-virgules dans les chaînes , elles seront considérées comme séparateurs!! ce qui entraîne des erreurs à la lecture; il faut mettre la chaîne entre "" ou bien remplacer le point-virgule par un caractère non utilisé (# par exemple) avant de l'enregistrer puis après la lecture remplacer '#' par ';'
Il faut utiliser Input pour relire ces données (Input utilise aussi le point-virgule comme séparateur.
La fonction WriteLine insère un
caractère de passage à la ligne, c'est-à-dire un retour chariot+ saut de ligne (Chr(13)
+ Chr(10)),On lira les
données par LineInput.
WriteLine(1,"toto")
WriteLine(1,"tata")
WriteLine(1, 1.2)
Donne le fichier
"toto"
"tata"
1.2
Il faut utiliser LineInput pour relire ces données car il lit jusqu'au retour Chariot, saut de ligne.
Toutes les données écrites dans le fichier à l'aide de la fonction Print respectent les conventions internationales ; autrement dit, les données sont mises en forme à l'aide du séparateur décimal approprié. Si l'utilisateur souhaite produire des données en vue d'une utilisation par plusieurs paramètres régionaux, il convient d'utiliser la fonction Write
EOF (NuméroFichier) veut dire 'End Of File', (Fin de Fichier) il prend la valeur True si on est à la fin du fichier et qu'il n'y a plus rien à lire.
LOF (NuméroFichier) veut dire 'Lenght Of File', il retourne la longueur du fichier.
Exemple: Lire chaque ligne d'un fichier texte.
Dim Line As String
FileOpen(1, "MonFichier.txt", OpenMode.Input) ' Ouvre en lecture.
While Not EOF(1) ' Boucler jusqu'à la fin du fichierLine = LineInput(1) ' Lire chaque ligne
Debug.WriteLine(Line) ' Afficher chaque ligne sur la console.
End While
FileClose(1) ' Fermer.
Ici on a utilisé une boucle While.. End While qui tourne tant que EOF est Faux. Quand on est à la fin du fichier EOF (End of File)devient égal à True et on sort de la boucle.
Fichier à accès aléatoire:
On ouvre le fichier avec FileOpen et le mode OpenMode.Random, ensuite on peut écrire un enregistrement grâce à FilePut() ou en lire un grâce à FileGet(). On peut se positionner sur un enregistrement précis (le 2eme, le 15ème) avec Seek.
Le premier enregistrement est l'enregistrement numéro 1
Exemple:
Fichier des adresses
Créer une structure Adresse, on utilise <VBFixedString(
)> pour fixer la longueur.
Public Structure Adresse
<VBFixedString(20)>Dim Nom As String
<VBFixedString(20)>Dim Rue As String
<VBFixedString(20)>Dim Ville As String
End Structure
'Ouvrir le fichier, comme il n'existe pas, cela entraîne sa création
Dim FileNum As Integer, RecLength As Long, UneAdresse As Adresse
' Calcul de la longueur de l'enregistrement
RecLength = Len(UneAdresse)
' Récupérer le premier numéro de fichier libre.
FileNum = FreeFile
' Ouvrir le fichier.
FileOpen(FileNum, "MONFICHIER.DAT", OpenMode.Random, , , RecLength)
Pour écrire des données sur le second enregistrement par exemple:
UneAdresse.Nom = "Philippe"
UneAdresse.Rue = "Grande rue"
UneAdresse.Ville = "Lyon"
FilePut(FileNum, UneAdresse,2 )
Dans cette ligne de code,
FileNum
contient le numéro
utilisé par la
2 est
le numéro de l'enregistrement ou sera copié la variable 'UneAdresse' (c'est un long si on utilise une
variable) et
UneAdresse, déclaré en tant
que type Adresse défini par l'utilisateur, reçoit le
contenu de l'enregistrement. Cela écrase l'enregistrement 2 s'il contenait
quelque chose.
Pour écrire à la fin du fichier, ajouter un enregistrement il faut connaître le nombre d'enregistrement et écrire l'enregistrement suivant.
Dim last as long 'noter que le numéro d'enregistrement est un long
Pour connaître le nombre d'enregistrement, il faut diviser la longueur du fichier par la longueur d'un enregistrement.
last = FileLen("MONFICHIER.DAT") / RecLength
On ajoute 1 pour créer un nouvel enregistrement.
FilePut(FileNum, UneAdresse,last+1 )
Pour lire un enregistrement (le premier par exemple):
FileGet(FileNum, UneAdresse, 1)
Attention Option Strict doit être à false .
Si option Strict est à True, la ligne qui précède génère une erreur car le second argument attendu ne peut pas être une variable 'structure'. Pour que le second argument de FileGet (Une adresse) soit converti dans une variable Structure automatiquement Option Strict doit donc être à false. (Il doit bien y avoir un moyen de travailler avec Option Strict On et de convertir explicitement mais je ne l'ai pas trouvé)
Remarque: si le fichier contient 4 enregistrements, on peut écrire le 10ème enregistrement, VB ajoute entre le 4ème et le 10ème, 5 enregistrements vides. On peut lire un enregistrement qui n'existe pas, cela ne déclenche pas d'erreur.
Le numéro d'enregistrement peut être omis dans ce cas c'est l'enregistrement courant qui est utilisé.
On positionne l'enregistrement courant avec Seek:
Exemple: Lire le 8ème enregistrement:
Seek(FileNum,8)
FileGet(FileNum,Une Adresse)
Vous pouvez supprimer le contenu d'un enregistrement en effaçant ses champs (enregistrer à la même position des variables vides), mais l'enregistrement existe toujours dans le fichier.
Pour enlever un enregistrement supprimé
Fichier binaire:
Dans les fichiers binaires on travaille sur les octets.
La syntaxe est la même que pour les fichiers Random, sauf qu'on travaille sur la position d'un octet et non sur un numéro d'enregistrement.
Pour ouvrir un fichier binaire:
FileOpen(FileNumber, FileName, OpenMode.Binary)
FileGet et FilePut permettent de lire ou d'écrire des octets .
FileOpen(iFr, ReadString, OpenMode.Binary)
MyString = New String(" "c, 15)
'Créer une chaîne de 15 espaces
FileGet(iFr, MyString)
' Lire 15 caractères dans MyString
FileClose(iFr)
MsgBox(MyString)
Le fait de créer une variable de 15 caractères et de l'utiliser dans FileGet
permet de lire 15 caractères.
C-Utilisation du Contrôle RichTextBox.
On rappelle que du texte présent dans un contrôle RichTextBox peut être enregistré ou lu très simplement avec les méthodes .SaveFile et .LoadFile.
Le texte peut être du texte brut ou du RTF.
richTextBox1.SaveFile(FileName, RichTextBoxStreamType.PlainText)
Si on remplace .PlainText par .RichText c’est le texte enrichi et non le texte brut qui est enregistré
Pour lire un fichier il faut employer .LoadFile avec la même syntaxe.
Simple, non!!!
Lire ou écrire des octets ou du XML:
BinaryWriter et BinaryReader permettent d'écrire ou de lire des données binaires.
XMLTextWriter et XMLTextReader écrit et lit du Xml.
Pour enregistrer un tableau, un objet, Vb.Net propose aussi la Sérialization (voir ce chapitre)
D- Comment ouvrir une boite de dialogue pour ouvrir un fichier?
Ajouter un contrôle OpenFileDialog à la form. (le nommer DialogOpen)
With DialogOpen
.InitialDirectory = "C:\LDF" 'répertoire sur lequel s'ouvrira la boite
.Title = "Choisir une fichier" 'titre de la barre
.Filter = "Fichiers LDF(*.ldf)|*.ldf" 'filtre, seules les fichiers LDF apparaîtront
.ShowDialog() ' on ouvre la boite de dialogue enfin
'Retour après la fermeture de la boite de dialogue
If Err.Number = 32755 Then Exit Sub 'le bouton 'annuler' a t'il été cliqué?
If Len(.FileName) = 0 Then Exit Sub 'aucun choix
sFile = .FileName 'nom du fichier choisi ( avec extension)
End With
Vous avez le nom du fichier a ouvrir, a vous de l'ouvrir avec un Open...
SaveFileDialog existe aussi.
Comment enregistrer, lire , effacer une variable structurée dans un fichier binaire:
Sans utiliser de FileOpen FilePut, FileGet mais en utilisant plutôt des FileStream (un BinaryReader et un BinaryWriter). On reste dans le Framework .Net et la programmation Objet.
Par Bruno Chappe.
Débutant s'abstenir.
Cette syntaxe est entièrement écrite en VB .NET 2005, et n’utilise que des objets avec méthodes et propriétés issue de VB .NET 2005.
On crée une Structure 'personne', une Class 'myBinaryReader', une Class 'myBinaryWriter' permettant de lire et d'enregistrer des 'personne'.
'System.IO doit être importé dans l'entête de votre module
ETAPE N°1 : Créer la structure et les classe binaryReader et binaryWriter personnalisées
'Créer la
structure avec son constructeur spécifique
Structure personne
Public pNom As String
Public
pPrenom As String
Public
pAge As Integer
Public
pMarie As Boolean
Sub
New ( ByVal myNom As String , ByVal myPrenom As String , ByVal myAge As Integer
, ByVal myMarie As Boolean )
Me.pNom = myNom
Me.pPrenom = myPrenom
Me.pAge = myAge
Me.pMarie
= myMarie
End
Sub
End
Structure
'Créer
une classe de binarywriter personnalisée à partir de le classe binarywriter
native de vb
Class
myBinarywriter
Inherits
System.IO.BinaryWriter
Sub
New ( ByVal st1 As System.IO.Stream )
MyBase.New(st1)
End
Sub
'PadRight est utilisé pour faire des chaînes de caractère de longueur fixes
'C'est
indispensable pour pouvoir calculer la longueur des enregistrements par la suite
et avoir des enregistrements qui ont tous la même longueur
Overloads
Sub write( ByVal e As personne )
MyBase.Write(e.pNom.PadRight(15))
MyBase.Write(e.pPrenom.PadRight(15))
MyBase.Write(e.pAge)
MyBase.Write(e.pMarie)
End
Sub
End Class
'Créer
une classe de binaryreader personnalisée à partir de la classe binaryreader
native de vb
Class
myBinaryreader
Inherits
System.IO.BinaryReader
Sub
New ( ByVal st2 As System.IO.Stream )
MyBase.New(st2)
End
Sub
Function
readpersonne() As personne
Dim
pNom As String = MyBase.ReadString
Dim
pPrenom As String = MyBase.ReadString
Dim
pAge As Integer = MyBase.ReadInt32
Dim
pMarie As Boolean = MyBase.ReadBoolean
readpersonne
= New personne(pNom, pPrenom, pAge, pMarie)
End
Function
End
Class
ETAPE N° 2 : Utilisation des classes personnalisées
***Ecrire un enregistrement
DEBUT
'Variable
string stockant le chemin d'accès au fichier
Dim myFile as String
'Si l'on
veut écrire directement dans un enregistrement existant (plutôt que d'écrire
à la suite du fichier)
'il faut
au préalable récupérer la rang de l'enregistrement ou l'on veut commencer à
écrire
'et
multiplier ce rang par la longueur d'un enregistrement (en octets). Cette opération
nous donne
'la
position du premier octet à écrire dans le fichier.
'Pour mémoire,
la longueur d'un enregistrement en octet est égale à la taille du fichier en
octet
'divisé
par le nombre d'enregistrements (Voir Annexe de ce document pour les
explications)
Dim position As Integer
'Déclarer
une variable de type 'personne' et assigner les valeurs voulues à ses champs
'Il est
possible de travailler avec un tableau de structure, cela revient au même mais
'est moins
indispensable qu'avant vu que l'on peut aller écrire et lire directement dans
le fichier
Dim maPersonne As personne
With maPersonne
.pNom = 'valeur du champ
.pPrenom = 'valeur du champ
.pAge = 'valeur du champ
.pMarie = 'valeur du champ
End With
'Déclare
le flux et le writer qui vont nous permettre d'écrire notre structure
'Bien
faire attention aux propriétés FileMode et FileAccess en fonction des opérations
'que vous
voulez effectuer
'Si vous
voulez écrire l'enregistrement à la suite des autres :
Dim
fs As FileStream = File.Open(myFile, FileMode.Append,
FileAccess.Write, FileShare.None)
'Si vous
voulez re-ecrire/modifier un enregistrement :
Dim
fs As FileStream = File.Open(myFile, FileMode.Open,
FileAccess.Write, FileShare.None)
'Dans les
2 cas, remarquez ici que nous instancions un objet issue de la classe que nous
avons créé plus haut
'et non
pas un objet issue des classes natives de vb
Dim bw As New myBinarywriter(fs)
'Nécessaire
que si vous souhaitez écrire à un endroit précis dans le fichier
'Où
position indique la position de début d'écriture dans le flux (fs) et
SeekOrigin.Begin indiquant à partir de quel
'endroit
du flux commencer la recherche de position
fs.Seek(position,
SeekOrigin.Begin)
'Dans tous
les cas, l'instruction ci-dessous écrit l'intégralité de notre structure sous
forme binaire dans le fichier
bw.write(maPersonne)
'SURTOUT
BIEN PENSER A FERMER LES FLUX ET WRITER
bw().Close
fs().Close
FIN
***Lire un enregistrement
DEBUT
'Variable
string stockant le chemin d'accès au fichier
Dim myFile as String
'Déclarer
la variable qui va recevoir les informations issues du fichier
Dim maPersonne As personne
'Instancier
un objet flux et un objet binaryReder
'Remarquez
le FileAcces.Read pour la lecture
Dim fs As FileStream = File.Open(myFile, FileMode.Open, FileAccess.Read, FileShare.None)
'Objet
instancié à partir de notre classe personnalisée myBinaryreader
Dim
br As New myBinaryreader(fs)
'Si besoin
d'aller lire un enregistrement précis
fs.Seek(position, SeekOrigin.Begin) 'Mêmes paramètres que pour l'écriture
'Sinon,
vous ferez probablement un traitement en boucle de tout les enregistrements du
fichier
Do Until fs.Position = fs.Length 'Faire jusqu'à ce que la position dans le flux soit égale à la longueur total du flux
myPersonne = br.readpersonne
'Ici
traitez les informations récupérées, par exemple pour afficher dans un
listBox
Loop
'SURTOUT
BIEN PENSER A FERMER LES FLUX ET READER
br().Close
fs().Close
FIN
***Supprimer un enregistrement
‘Au
préalable il faut “marquer” l’enregistrement à effacer en utilisant la
procédure décrite plus haut pour modifier un enregistrement. Pour cela on peut
faire soit comme dans le TP en utilisant un champ « supprimé »de
notre structure que l’on marque à True soit on écrit un enregistrement vide
par-dessus l’enregistrement que l’on veut effacer (en affectant « Nothing »
au premier champ de l’enregistrement par exemple). En résumé, n’importe
quoi qui nous permet de repérer au moment de la réécriture du fichier, que
cet enregistrement ne doit pas être recopié.
‘Commencer
par créer une copie du fichier original (Ne pas oublier de faire des tests sur
l’existence du fichier)
Dim
fi As New FileInfo(myFile)
Dim
newFile As String = myFile & “.bck”
fi.CopyTo(newFile)
‘Créé
newFile et copie myFile dedans
‘Ensuite on ouvre les 2 flux (1 en lecture et 1 en écriture) et les 2 binary (-reader & -writer)
Dim
fsR As FileStream = File.Open(newFile, FileMode.Open, FileAccess.Read,
FileShare.None)
‘Ici
le le paramètre FileMode.Create va faire que le fichier myFile va être recréé
par-dessus l’ancien fichier et l’écraser
Dim
fsW As FileStream = File.Open(myFile, FileMode.Create, FileAccess.Write,
FileShare.None)
‘Après
l’instruction ci-dessus on a donc un fichier myFile qui existe mais qui est
vide (sans avoir besoin de le supprimer d’abords et de le recréer ensuite),
prêt à recevoir les données du fichier newFile.
Dim
br As New myBinaryreader(fsR)
Dim
bw As New myBinarywriter(fsW)
‘On
dimensionne une variable du type de notre structure
Dim maPersonne As personne
‘Faire
une boucle sur le fichier en lecture
Do Until fsR.Position = fsR.Length
maPersonne = br.readpersonne
‘Si marquage de maPersonne n’indique pas qu’il faut effacer l’enregistrement alors :
bw.write(maPersonne)
End If
Loop
‘Cette
boucle va donc lire chaque enregistrement dans newFile, l’affecter dans une
variable structurée maPersonne et si cette variable ne contient pas
d’indicateur de suppression, l’écrire dans myFile. A la fin de la boucle
myFile contient donc tous les enregistrements de newFile sauf ceux marqués à
supprimer.
‘On
oubli pas de fermer les flux
br.Close()
bw.Close()
fsR.Close()
fsW.Close()
‘Et
de supprimer le fichier newFile qui ne nous sert plus à rien
File.Delete(newFile)
ANNEXE : Comment calculer la valeur de la variable « position » utilisée dans la méthode seek de notre FileStream
Nous avons besoin de 3 éléments : la longueur totale du fichier en octets, la taille d’un enregistrement en octets, le numéro de l’enregistrement que l’on souhaite modifier/remplacer/effacer.
Longueur totale du fichier en octets
Dim
fi as New FileInfo(myFile)
Dim longueurFichier As Long
longueurFichier
= fi.length ‘Renvoi
un entier long représentant la taille totale en octet
Taille d’un enregistrement en octets
Dim nbEnreg As Integer ‘Au préalable il faut récupérer le nombre d’enregistrements, par exemple lors d’une première lecture du fichier séquentielle, en incrémentant un compteur par programmation.
Dim
tailleEnreg as Integer
tailleEnreg = longueurFichier / nbEnreg
Pointer directement dans le fichier à l’octet voulu pour l’écriture
Autrement dit, calculer la variable « position » pour pouvoir l’utiliser dans la méthode seek.
Il suffit de multiplier le numéro de l’enregistrement à écrire (le premier enregistrement doit avoir l’indice 0) par la taille d’un enregistrement.
Ainsi par exemple, si j’ai un fichier de 120 octets avec 12 enregistrements (de 0 à 11), cela me fait des enregistrements de 10 octets de long. Si je veux aller modifier le 4ème enregistrement, ma variable position sera égale à 40 (4*10).
Il ne me reste plus qu’à déplacer le pointeur dans mon flux avant d’écrire ma variable, en utilisant :
fs.Seek(position,
SeekOrigin.Begin)
|
|
|
|
|