Les fichiers▲
But de ce chapitre▲
En utilisant ce que nous avons vu dans les cours précédents, vous ne pouvez pas réaliser un programme qui serait capable de conserver ses résultats une fois l'ordinateur éteint. D'autre part, les données doivent être nécessairement fournies par l'utilisateur à chaque exécution du programme. Ces limitations proviennent du type de mémoire utilisé : pour l'instant, vous ne savez traiter que des données stockées en mémoire vive. Or, la mémoire vive est volatile : lorsque l'ordinateur est mis hors tension, tout disparaît !
Ce problème pourrait donc être donc résolu si vous connaissiez les instructions permettant de lire ou d'enregistrer des données dans des mémoires non volatiles, stockées par exemple sur le disque dur ou sur une clé USB, sous la forme de fichiers.
L'objectif de ce cours est de vous décrire précisément les procédures Pascal réalisant ceci.
Notion de fichier▲
Qu'est-ce qu'un fichier ?▲
Un fichier est un ensemble de données informatiques stockées en mémoire auxiliaire (disque dur, CD, DVD, clef USB…) possédant un nom, un chemin d'accès et généralement implicitement associé à un format (format image, format de documents, formats de base de données…).
Le terme de mémoire auxiliaire désigne tout support de stockage de l'information d'un ordinateur autre que la mémoire vive.
Le fait qu'un fichier soit toujours stocké sur mémoire auxiliaire a deux conséquences.
Premièrement, les données contenues dans un fichier ne sont pas perdues lorsque l'ordinateur est mis hors tension (contrairement aux données contenues dans les variables d'un programme !).
Deuxièmement, l'accès à des données stockées dans un fichier est considérablement plus lent qu'un accès à des données contenues en mémoire vive.
Nom de fichier▲
La manière de nommer les fichiers dépend fortement du système d'exploitation. Par exemple, sous Windows, tout fichier possède généralement une extension (.doc, .jpg…) qui permet d'identifier son format.
Chemin d'accès▲
Le chemin d'accès d'un fichier définit sa localisation sur un périphérique donné. C'est une chaîne de caractères qui définit la suite des répertoires à parcourir pour atteindre le fichier depuis la racine du périphérique.
La manière de décrire un chemin dépend du système d'exploitation. Sous Windows, un chemin est une chaîne de caractères de la forme :
X:\Répertoire\Répertoire\ ... \Répertoire
où X est une lettre définissant le périphérique utilisé.
Par exemple :
C:\Utilisateurs\Thirion\Documents
Identification d'un fichier par son nom complet▲
Le nom d'un fichier ne l'identifie pas de manière unique. Par exemple, il peut exister un fichier nommé CV.doc sous
C:\Utilisateurs\Thirion\Documents
et un autre sous
C:\Utilisateurs\Einstein\Documents
Pour identifier un fichier de manière unique, il faut utiliser son chemin concaténé avec le nom (simple) du fichier. Par exemple :
C:\Utilisateurs\Thirion\Documents\CV.doc
désigne le CV de Thirion, alors que :
C:\Utilisateurs\Einstein\Documents\CV.doc
désigne le CV de Einstein.
J'utiliserai par la suite le terme de nom complet, pour désigner le chemin concaténé avec le nom du fichier.
Format▲
Le format d'un fichier est un ensemble de conventions définissant la représentation des données qu'il contient : la localisation et le codage des différents types d'informations contenues dans le fichier.
Le fichier en lui-même ne permet pas à coup sûr de retrouver son format de manière immédiate : comme toute chose en informatique, ce n'est qu'une suite de zéros et de uns. Une manière de vérifier si un fichier est bien dans un format donné est de l'ouvrir avec un logiciel adapté à ce format. Si le logiciel gère correctement le fichier, il est certainement dans le bon format (mais ce n'est pas une certitude !). Une autre manière est de scruter l'en-tête du fichier à la recherche d'une signature numérique propre à son format.
Exemple : si je peux ouvrir un fichier avec Word, il s'agit très certainement d'un fichier respectant un des formats acceptés par Word (.doc, .txt…). Au contraire, si j'essaie d'ouvrir avec Word un fichier qui n'est pas dans un format accepté par Word, il se produira probablement n'importe quoi.
Sous Windows, le format d'un fichier est repérable par l'extension (.doc pour un fichier Word, .exe pour un fichier exécutable…). Mais l'extension d'un fichier peut être changée manuellement… L'extension d'un fichier ne donne donc aucune certitude sur son format !
Les fichiers texte▲
Les fichiers texte sont des fichiers que l'on peut ouvrir avec un éditeur de texte (comme WordPad ou le Bloc-notes) afin de modifier leur contenu.
Ce sont par exemple les fichiers d'extension .txt sous Windows, les fichiers sources d'un programme, les fichiers HTML, etc.).
Un fichier texte est un fichier qui peut être interprété comme une suite de caractères (le plus souvent en code ASCII) affichables à l'écran.
Deux caractères spéciaux servent à coder le passage à la ligne et la fin du fichier.
Les fichiers structurés▲
Les fichiers structurés sont des fichiers interprétables comme une suite d'enregistrements d'un certain type. Tous les enregistrements sont forcément de même taille.
Les fichiers structurés peuvent être vus comme la représentation d'un tableau en mémoire auxiliaire. Rappelez-vous que tous les éléments d'un tableau doivent être de même type. Les éléments du tableau correspondent ici aux enregistrements.
Certains auteurs utilisent le nom de fichiers séquentiels pour désigner des fichiers structurés. Je trouve ce nom très mal adapté car il porte à confusion. Nous verrons pourquoi un peu plus loin.
Opérations sur les fichiers▲
Les langages de programmation permettent de :
- créer des fichiers ;
- enregistrer des informations dans un fichier : c'est l'accès en écriture ;
- lire des informations dans un fichier : c'est l'accès en lecture.
Les erreurs d'accès▲
Le système d'exploitation est responsable de la gestion des fichiers d'un ordinateur. Toute opération sur un fichier se fait donc nécessairement par l'intermédiaire du système d'exploitation. Lorsqu'un programme effectue une opération sur un fichier, il faut que le système d'exploitation autorise cette opération, sans quoi il se produira une erreur d'accès :
Voilà quelques-unes des erreurs les plus fréquentes :
- vous faites un accès en lecture sur un fichier qui n'existe pas ;
- vous faites un accès en lecture sur un fichier, alors que vous n'avez pas de droit de lecture sur ce fichier : ce fichier appartient à un autre utilisateur, c'est un fichier protégé, etc. ;
- vous faites un accès en écriture sur un fichier, alors que vous n'avez pas de droit d'écriture sur ce fichier ;
- vous faites un accès en écriture sur un fichier alors qu'un autre programme est en train d'y accéder en lecture ou en écriture ;
- vous faites un accès en écriture sur un fichier alors que le périphérique qui le contient est plein ;
- vous faites un accès en lecture ou en écriture « en dehors » du fichier.
Ouverture et fermeture d'un fichier▲
L'accès à un fichier par programmation fonctionne toujours selon le même principe :
- avant de lire ou d'écrire des informations dans un fichier, il faut l'ouvrir ;
- lorsque le traitement du fichier est terminé il faut le fermer.
À quoi sert l'ouverture d'un fichier ?▲
Ouvrir un fichier sert (entre autres) à informer le système d'exploitation que l'on a l'intention d'y accéder. C'est à ce moment-là que le système peut refuser l'accès au fichier, ce qui provoquera une erreur d'exécution du programme.
À quoi sert la fermeture d'un fichier ?▲
La fermeture d'un fichier sert (entre autres) à signaler au système d'exploitation que le fichier n'est plus utilisé par le programme, ce qui permettra à un autre programme (éventuellement d'un autre utilisateur) d'y accéder.
Accès direct et accès séquentiel▲
Il y a deux manières d'accéder à un fichier par programmation : l'accès direct et l'accès séquentiel.
Accès direct▲
L'accès direct n'est possible que pour des fichiers définis comme une suite de blocs de taille fixe que l'on appelle enregistrements. Il n'est donc possible que pour les fichiers structurés.
L'accès direct signifie qu'il est possible d'accéder directement à un enregistrement à partir de sa position dans le fichier : lire le énième enregistrement du fichier ou le modifier. Ce type d'accès est par exemple adapté à la gestion des tables d'une base de données.
Accès séquentiel▲
Dans l'accès séquentiel, une opération de lecture ou d'écriture se fait toujours juste après la dernière partie du fichier lue ou écrite.
Les fichiers texte n'autorisent que ce type d'accès.
Les fichiers structurés quant à eux autorisent les deux types d'accès (séquentiel ou direct).
Vous comprenez à présent pourquoi le fait d'appeler « fichiers séquentiels » les fichiers structurés est une source de confusion !
Manipulation des fichiers texte▲
Ouverture d'un fichier texte▲
L'ouverture d'un fichier texte se fait en lecture, en écriture ou en ajout. Nous ne traiterons pas ici de l'ouverture en ajout.
Si le fichier est ouvert en lecture, il ne peut y avoir que des lectures jusqu'Ã la fermeture du fichier.
De même, si le fichier est ouvert en écriture, il ne peut y avoir que des écritures jusqu'à la fermeture du fichier.
Opérations sur les lignes▲
Un fichier texte est normalement organisé en lignes. Les langages de programmation contiennent en général une instruction (ou une procédure) permettant de :
- lire une ligne du fichier en la recopiant dans une variable de type chaîne de caractères. Cette opération n'est possible que si le fichier est ouvert en lecture. De plus, comme il s'agit d'un accès séquentiel, elle se fait forcément juste après la dernière ligne lue. Sauf si le fichier vient d'être ouvert. Dans ce cas, la ligne lue est nécessairement la première ligne du fichier ;
- écrire une chaîne de caractères dans une ligne du fichier. De même, cette opération n'est possible que si le fichier est ouvert en écriture et se fait forcément juste après la dernière ligne écrite. Exception pour l'écriture d'une ligne qui suit immédiatement l'ouverture du fichier : ce sera forcément la première ligne du fichier.
Manipulation des fichiers structurés▲
Ouverture d'un fichier structuré▲
Pour ouvrir un fichier structuré, il n'est pas nécessaire de préciser si l'on veut ouvrir le fichier en lecture ou en écriture. En effet, avec un fichier structuré, ces deux types d'opérations (lecture et écriture) peuvent être mélangées dans n'importe quel ordre.
Si le fichier n'existe pas avant l'ouverture, il sera créé.
Accès séquentiel▲
L'accès séquentiel dans un fichier structuré consiste à lire ou à écrire un enregistrement sans préciser sa position. La lecture ou l'écriture se fait nécessairement juste après le dernier enregistrement lu ou écrit. Sauf si le fichier vient juste d'être ouvert. Dans ce cas, l'enregistrement lu ou écrit sera forcément le premier.
Accès direct▲
Dans l'accès direct, on accède à un enregistrement par sa position dans le fichier. Il est par exemple possible de lire le 25e enregistrement, puis de modifier le 122e. On peut parcourir le fichier dans n'importe quel ordre.
Manipulation de fichiers texte en Pascal▲
Déclaration▲
Un fichier texte est représenté en Pascal par le type TextFile. Pour pouvoir manipuler un fichier texte, il faut d'abord déclarer une variable de ce type. Par exemple :
var
f : TextFile;
Dans toutes les explications qui suivent, f désignera le fichier déclaré de cette manière.
Assignation▲
Avant de pouvoir ouvrir un nouveau fichier texte, il faut d'abord associer la variable fichier au nom du fichier sur le disque. Cela se fait par la procédure AssignFile. Voici, par exemple, comment associer f à un fichier nommé exemple.txt :
AssignFile(f,'exemple.txt'
);
Création d'un fichier texte▲
Ouverture en écriture▲
Après avoir déclaré une variable de type fichier et assigné cette variable à un nom de fichier, on peut l'ouvrir en écriture. Cela a pour effet de créer un nouveau fichier vide. Attention : s'il existe déjà un fichier de même nom sur le disque, le contenu de ce dernier sera perdu !
L'ouverture en écriture, se fait par la procédure rewrite, comme suit :
rewrite(f);
Écriture d'une ligne▲
Dès que le fichier est ouvert en écriture, on peut y écrire du texte en utilisant la procédure writeln. Voici, par exemple, comment créer un fichier texte exemple.txt d'une ligne :
var
f: TextFile;
begin
assign (f,'exemple.txt'
);
rewrite(f);
writeln (f,'Ceci est un fichier d'
une ligne.');
CloseFile(f);
end
;
La procédure CloseFile appelée à la fin sert à fermer le fichier.
Comme on fait de l'accès séquentiel, une écriture se fait forcément après la ligne écrite juste avant. Donc, après l'exécution du code suivant :
var
f: TextFile;
begin
assign(f,'exemple.txt'
);
rewrite(f);
writeln(f,'Première ligne du fichier exemple.txt'
);
writeln(f,'Deuxième ligne du fichier exemple.txt'
);
CloseFile(f);
end
;
le fichier exemple.txt contiendra les deux lignes :
Première ligne du fichier exemple.txt
Deuxième ligne du fichier exemple.txt
Lecture d'un fichier texte▲
Ouverture d'un fichier texte en lecture▲
Pour ouvrir un fichier en lecture, on utilise la procédure reset de la manière suivante :
reset(f);
Comme pour l'ouverture en écriture, il faut que le fichier ait auparavant été assigné à un nom de fichier. Par contre, si ce fichier n'existe pas, cela provoquera une erreur.
Lecture d'une ligne et test de fin de fichier▲
Pour lire une ligne dans le fichier, on utilise la procédure readln, qui affecte la ligne courante à une variable L de type chaîne de caractères :
readln(f,L);
Il s'agit ici d'un accès séquentiel, donc une lecture de ligne se fait nécessairement juste après la ligne lue précédemment.
Juste après l'ouverture du fichier, readln transfère la première ligne du fichier dans variable L.
À la deuxième exécution de cette procédure, L contiendra la 2e ligne du fichier et de manière générale, après la énième exécution, L contiendra la énième ligne du fichier.
Bien entendu, on provoquera une erreur d'exécution si l'on essaie de lire au-delà de la fin du fichier. Par exemple, si le fichier exemple.txt ne contient que 10 lignes, la 11e exécution de readln(f,L); provoquera une erreur d'exécution.
Pour éviter cette erreur, il faut utiliser la fonction eof, qui permet de tester si l'on se trouve en fin de fichier. Par exemple, le code suivant permet de lire toutes les lignes du fichier exemple.txt afin d'effectuer un certain traitement sur chaque ligne :
Var
f : TextFile; L : String
;
begin
assign(f,'exemple.txt'
);
reset(f);
while
not
eof(f) do
begin
readln(f,L);
// Traitement de la ligne L
end
;
CloseFile(f);
end
;
Les fichier structurés en Pascal▲
Déclaration▲
Un fichier structuré est un fichier constitué d'enregistrements de même type.
Le type d'un enregistrement est a priori n'importe quel type Pascal de taille fixe. En effet, comme chaque enregistrement doit occuper la même taille en mémoire auxiliaire, on ne peut pas déclarer un fichier constitué d'enregistrements de longueur variable. En particulier, le type String sera interdit et devra être remplacé par le type String[n], qui permet de préciser la taille de la chaîne de caractères.
Pour la suite des explications, nous allons utiliser le type structuré Livre déclaré comme suit :
Livre =
record
Titre : String
[100
];
Auteur : String
[20
];
AnnéePub : integer
;
end
;
Nous pouvons ensuite déclarer un fichier structuré composé d'enregistrements de type Livre comme suit :
var
f : file
of
Livre;
Remarquez que le type des enregistrements d'un fichier structuré n'est pas forcément un type structuré. On peut par exemple déclarer un fichier d'entiers (file of integer) ou un fichier de caractères (file of char).
Assignation▲
Tout comme pour les fichiers texte, avant d'ouvrir un fichier structuré il faut associer la variable représentant le fichier à un nom de fichier avec la procédure AssignFile.
Exemple :
AssignFile(f,'Bibliotheque.dat'
);
Cette instruction assigne f au fichier de nom Bibliotheque.dat.
Ouverture et fermeture▲
Pour ouvrir des fichiers structurés, on utilise encore les procédures reset et rewrite. Mais elles n'ont pas la même signification que pour les fichiers texte.
En effet, il sera toujours possible de lire et d'écrire des enregistrements, que le fichier soit ouvert avec reset (ouverture en lecture pour un fichier texte) ou avec rewrite (ouverture en écriture pour un fichier texte).
Pour les fichiers structurés, rewrite n'est pas une ouverture en écriture. Cela signifie seulement que l'on demande au système d'exploitation de créer un nouveau fichier. Avec reset, on demande simplement l'ouverture, sans création d'un nouveau fichier.
Par contre, un fichier ne peut pas être ouvert avec reset s'il n'existe pas. Pour ouvrir un fichier structuré sans savoir auparavant s'il existe ou non, on utilisera la fonction FileExists (fonction permettant de tester l'existence d'un fichier de nom donné) de la manière suivante :
if
FileExists('Bibliotheque.dat'
) then
reset(f)
else
rewrite(f);
Écriture séquentielle▲
L'écriture d'un enregistrement se fait avec la procédure write. Plus précisément, write (f,v) écrit la valeur de la variable v dans le fichier f à la suite du dernier enregistrement lu ou écrit. Bien entendu, la variable doit être de même type que les enregistrements du fichier.
Si le fichier vient d'être ouvert, l'écriture se fait dans le premier enregistrement.
Déclarons par exemple deux structures de type Livre :
var
VB, Gaston : Livre;
Donnons des valeurs à leurs champs :
VB.Titre := 'Visual Basic 6, Le guide du programmeur'
;
VB.Auteur := 'Frantz'
;
VB.AnneePub := 2000
;
Gaston.Titre := 'Gaston Lagaffe - Des Gaffes et des Dégâts'
;
Gaston.Auteur := 'Franquin'
;
Gaston.AnneePub := 1975
;
Après les instructions suivantes :
AssignFile(f,'Bibliotheque.dat'
);
rewrite(f);
write
(f,Gaston);
write
(f,VB);
le fichier Bibliotheque.dat contiendra deux enregistrements de type Livre. Plus précisément, le premier enregistrement contiendra le livre Gaston et le deuxième, le livre VB.
Si, après cela, on fait encore une fois
write
(f,Gaston);
le fichier contiendra trois enregistrements (Gaston, VB, Gaston).
Si on écrit un enregistrement juste après l'ouverture d'un fichier existant (donc avec un reset), cette écriture se fera dans le premier enregistrement du fichier. Par exemple, après l'exécution du code suivant :
AssignFile(f,'Bibliotheque.dat'
);
reset(f);
write
(f, VB);
le fichier contiendra (VB, VB, Gaston).
Lecture séquentielle▲
La lecture d'un enregistrement à la suite du dernier enregistrement lu ou écrit se fait par la procédure read. Plus précisément, pour affecter la valeur d'un enregistrement à une variable v, on écrira read(f,v). Cela suppose bien entendu que la variable est du même type que les enregistrements du fichier.
Si le fichier vient d'être ouvert, l'enregistrement lu sera le premier.
Reprenons la suite de l'exemple précédent. Notre fichier Bibliotheque.dat contient à présent trois enregistrements de type Livre (VB, VB, Gaston).
Pour les récupérer, déclarons trois variables de type Livre :
var
Livre1, Livre2, Livre3 : Livre;
Après les instructions suivantes :
AssignFile(f,'Bibliotheque.dat'
);
reset(f);
read
(f,Livre1);
read
(f,Livre2);
read
(f,Livre3);
les structures Livre1 et Livre2 contiendront le livre VB et Livre3 contiendra le livre Gaston.
Lecture jusqu'en fin de fichier▲
De manière générale, on ne connaît pas le nombre d'enregistrements contenus dans un fichier structuré. On utilise alors la fonction eof pour savoir si on est arrivé à la fin du fichier. Voici comment lire séquentiellement un fichier structuré afin d'effectuer un traitement sur chacun de ses enregistrements :
var
f : file
of
type
;
x : type
;
AssignFile(f,'Bibliotheque.dat'
);
reset(f);
while
not
eof(f) do
begin
read
(f,x);
// Traitement de l'enregistrement x
end
;
Exercices▲
Téléchargez les exercices sur le site de l'auteur :
Pour obtenir les corrigés, le téléchargement n'est possible que via un login et un mot de passe, que vous pouvez obtenir en envoyant un mail à l'adresse suivante :
en précisant un peu qui vous êtes et les raisons pour lesquelles ce cours vous intéresse.