7

La notion de fichier

Nous avons vu dans les premiers chapitres que l'un des rôles du système d'exploitation était de fournir à l'utilisateur une machine virtuelle adaptée à ses besoins. Les connexions avec les périphériques présentant des formes variées, il est nécessaire d'étudier quels sont les vrais besoins des utilisateurs pour réaliser cette adaptation.
Rappelons, tout d'abord, que nous avons distingué quatre sortes de périphériques:

7.1. Le but des objets externes

Rappelons que lors de l'exécution d'un programme, le processeur ne manipule que des objets en mémoire centrale, dont les caractéristiques générales imposent que de tels objets ne puissent, en général, exister avant le chargement du programme, ou après la fin de son exécution. Leur durée de vie est limitée à la durée de présence du programme en mémoire. On dit que ces objets sont internes au programme. Par opposition, on appelle objet externe ceux qui ne sont pas internes.

7.1.1. Les objets externes comme outils d'échange d'informations

On peut distinguer deux objectifs dans l'utilisation des objets externes par un programme. Le premier est l'échange d'informations, qu'il soit avec l'homme ou avec une autre machine. La conséquence de cet échange est la nécessité de trouver un langage commun entre les deux partenaires de l'échange.
Avec l'homme comme partenaire, cela implique la transformation de la représentation interne des données en une forme compréhensible par l'homme, et réciproquement.
Lors de l'échange entre machines, plusieurs solutions peuvent être adoptées, suivant la nature des machines qui communiquent. Notons tout d'abord que l'échange de base est réalisé sous forme d'une suite d'octets. À l'émission, la représentation interne des données doit donc être convertie en une suite d'octets, et l'opération inverse effectuée à la réception. Les données déjà sous forme de suite d'octets, comme par exemple les chaînes de caractères, ne posent en général pas de difficulté, du moins si les deux machines utilisent le même codage des caractères (il en existe deux principaux: EBCDIC et ASCII). Les données dont la représentation interne regroupe plusieurs octets posent plus de difficultés.
Si les représentations des données sont les mêmes pour les deux machines, en particulier si elles sont du même modèle, la communication peut se faire en binaire, c'est-à-dire, dans la représentation interne commune. Si ce n'est pas le cas, on peut faire, sur l'une des machines ou sur l'autre, la conversion entre les représentations binaires. Une dernière solution plus courante est d'utiliser une représentation normalisée des données pour assurer l'échange d'informations entre ces machines. L'avantage, dans ce cas, est que le producteur de l'information n'a pas à se préoccuper du destinataire, et réciproquement. L'inconvénient est, bien entendu, la perte de temps machine qui résulte de ces conversions.
Notons que cette conversion de données est considérée comme suffisamment importante pour que certains langages de programmation comme le COBOL permettent de les réduire au minimum. Les données conservent alors dans le programme leur représentation externe. La conversion éventuelle n'intervient alors que lorsque les traitements le nécessitent. Le programmeur doit évidemment avoir conscience du compromis qu'il doit choisir:

7.1.2. Les objets externes comme outils de mémorisation à long terme

Un programmeur a aussi besoin des objets externes pour disposer d'informations dont la durée de vie s'étend au-delà de la durée de vie du programme. C'est le cas lorsque ces données existent avant le chargement du programme, ou doivent être conservées après la fin de son exécution.
Contrairement au cas précédent, c'est la même machine qui crée ces données et les reprend ultérieurement[1]. On peut dire effectivement qu'il s'agit encore de pouvoir échanger des informations mais cette fois entre des programmes qui s'exécutent sur la même installation. Le problème de conversion énoncé ci-dessus ne se pose plus. Les données, en général, peuvent et doivent être mémorisées dans leur représentation interne.
Un problème peut cependant se poser pour les données de type pointeur. Rappelons qu'un pointeur est une information binaire qui permet de désigner un emplacement dans un espace mémoire; c'est donc une adresse. Si cette mémoire est la mémoire centrale, cela signifie que le pointeur désigne un objet interne au programme, et n'a de signification que pour cette exécution. Le conserver sous cette forme après la fin de l'exécution de ce programme n'a pas sens. Sa valeur doit être remplacée par une information qui désigne l'emplacement dans l'objet externe où sera rangé la copie de la donnée interne pointée.

7.2. La manipulation des objets externes par le programme

Le mot fichier est parfois utilisé de façon ambiguë, car il désigne tantôt l'objet externe mémorisé sur un support magnétique (bande ou disque), tantôt l'entité manipulée par le programme. Pour éviter cette ambiguïté, le premier pourrait être appelé fichier physique et le second fichier logique. En général nous n'utiliserons le terme fichier que pour désigner la façon dont le programme manipule l'objet indépendamment de l'objet lui-même et des contraintes physiques d'implantation comme des caractéristiques du périphérique qui le supporte.

7.2.1. La notion de fichier

Le fichier est la façon dont un programme voit un objet externe. C'est d'abord une collection d'enregistrements logiques éventuellement structurée, sur laquelle le programme peut exécuter un ensemble d'opérations. Un enregistrement logique, encore appelé article, est l'ensemble minimum de données qui peut être manipulé par une seule opération élémentaire du fichier. Il est souvent constitué de diverses données élémentaires, que l'on peut décrire dans le langage de programmation utilisé, comme le montre la figure 7.1. Ces données élémentaires ne sont accessibles individuellement par le programme que lorsque l'enregistrement logique est recopié dans un objet interne au programme. Dans cet exemple, le fichier est constitué d'une collection d'enregistrements qui ont la structure d'EMPLOYE. Les opérations sur le fichier permettent de transférer le contenu d'un tel enregistrement entre la mémoire interne du programme et l'objet externe qui lui est associé.
		01 EMPLOYE
			02 NOM PICTURE X(30)
			02 PRENOM PICTURE X(20)
			02 NUM-S-S
				03 SEXE PICTURE 9
				03 DATE-NAISSANCE
					04 ANNEE PICTURE 99
					04 MOIS PICTURE 99
				03 LIEU-NAISSANCE
					04 DEPARTEMENT PICTURE 99
					04 CANTON PICTURE 999
				03 ORDRE PICTURE 999
			02 CODE-INTERNE PICTURE 9999
Fig. 7.1. Exemple de description en COBOL d'un enregistrement logique.

7.2.2. Le fichier séquentiel

La caractérisation des fichiers est déterminée par la nature des opérations que l'on peut effectuer sur le fichier. Le plus simple est le fichier séquentiel. Les opérations se résument, essentiellement, en la lecture de l'enregistrement suivant ou l'écriture d'un nouvel enregistrement en fin du fichier séquentiel. Bien souvent, pour affirmer le caractère séquentiel du fichier, il n'est pas possible de mélanger les lectures et les écritures. Le fichier est alors un fichier séquentiel en lecture ou un fichier séquentiel en écriture.
Le fichier séquentiel en lecture est initialement positionné sur le premier enregistrement logique. Chaque opération de lecture (lire ou read) transfère dans une zone interne au programme un enregistrement du fichier, et prépare le fichier pour le positionner sur l'enregistrement suivant. On dispose souvent d'une opération complémentaire qui permet de savoir s'il y a encore des enregistrements à lire dans le fichier (fin_de_fichier ou end_of_file), et éventuellement une opération permettant le retour au début du fichier (rembobiner ou rewind).
Le fichier séquentiel en écriture peut être initialement vide, ou positionné après le dernier enregistrement déjà dans le fichier. Chaque opération d'écriture (ecrire ou write) rajoute un enregistrement dans le fichier depuis une zone interne au programme, et positionne le fichier après cet enregistrement. L'écriture d'un enregistrement se fait donc toujours après ceux qui sont déjà dans le fichier.
Noter que la caractéristique essentielle d'un fichier séquentiel est que les enregistrements sont lus dans l'ordre où ils ont été écrits. Aucune conversion des données n'est appliquée, soit parce qu'elle est faite par le programme, soit parce qu'elle n'est pas nécessaire.

7.2.3. Le fichier séquentiel de texte

Le fichier séquentiel de texte est analogue à un fichier séquentiel, mais avec conversion du format des données entre leur représentation interne et une représentation accessible à l'être humain. L'expression des opérations nécessitant la définition d'un format de conversion, la forme est très dépendante du langage de programmation. On peut assimiler un fichier séquentiel de texte à un fichier séquentiel où les enregistrements logiques sont en fait des caractères individuels.
En lecture, les opérations sur un tel fichier sont complétées par des opérations qui permettent de lire une donnée élémentaire, comme un entier, un nombre flottant, etc..., par conversion d'une suite de caractères lus depuis le fichier, suivant un certain format, implicite ou explicite.
En écriture, les opérations sur un tel fichier sont complétées par des opérations qui permettent d'écrire une donnée élémentaire, comme un entier, un nombre flottant, etc..., par conversion en une suite de caractères écrits dans le fichier, suivant un certain format, implicite ou explicite.
Certains langages de programmation, comme le FORTRAN, présentent le fichier séquentiel comme une collection d'enregistrements logiques correspondant à une ligne de texte. En lecture, on peut alors lire l'enregistrement complet, par le biais d'un format, et d'un ensemble de variables élémentaires. Le format est alors utilisé pour découper l'enregistrement en chaînes de caractères et les convertir dans la représentation interne de ces variables. De même, en écriture, on peut écrire un enregistrement complet, par le biais d'un format et d'un ensemble de valeurs élémentaires. Le format permet de convertir ces valeurs en leur représentation externe et de les placer dans l'enregistrement.

7.2.4. Le fichier à accès aléatoire

Le but du fichier aléatoire est de permettre l'accès à un enregistrement quelconque de la collection sans avoir à parcourir tous ceux qui ont été écrits avant lui. En général, il n'y a pas de restriction du type lecture seule ou écriture seule, comme dans les fichiers séquentiels, mais au contraire définition de trois opérations principales: lecture, écriture et mise à jour d'un enregistrement après sa lecture.
Pour fournir l'accès à l'un quelconque des enregistrements, il faut que le programmeur puisse le désigner. Cette désignation peut se faire par un numéro. Dans ce cas, le fichier est vu comme une collection d'enregistrements numérotés. Pour permettre d'implanter efficacement l'accès à un enregistrement de numéro donné, la taille d'un enregistrement, c'est-à-dire, le nombre d'octets de sa représentation, est en général fixe. Pour le programmeur, le fichier à accès aléatoire par numéro peut s'assimiler à un tableau à une dimension. C'est évidemment lui qui fixe l'attribution des numéros aux enregistrements lors des écritures.
La désignation d'un enregistrement peut se faire par l'intermédiaire d'une clé qui est en général incluse dans l'enregistrement. Lors d'une lecture, le programmeur peut, par exemple, donner d'abord une valeur aux champs correspondant à la clé dans la zone mémoire interne de l'enregistrement, et en demander la lecture. L'opération du fichier recherchera l'enregistrement correspondant et en rangera la valeur dans la zone. L'opération de mise à jour ou update, ultérieure réécrira cet enregistrement sans avoir besoin de le rechercher de nouveau. Une opération d'écriture, avec en paramètre le contenu de l'enregistrement dans une zone en mémoire interne, consistera à placer l'enregistrement dans l'objet externe, et à mettre à jour la structure de données qui permet de le retrouver (fichier séquentiel indexé ou B-arbre).
On trouve parfois un troisième type de fichier à accès aléatoire construit sur un fichier séquentiel, mais qui ne doit pas être confondu avec ce dernier. On dispose dans ce cas des deux opérations de lecture séquentielle et d'écriture séquentielle (au bout), ainsi que de deux opérations supplémentaires permettant l'accès aléatoire aux enregistrements du fichier:
L'utilisation de ces opérations permet au programmeur de construire des structures de données quelconques sur un fichier. La valeur retournée par noter peut s'assimiler à un pointeur externe et n'a de sens que sur le fichier dont il provient.

7.3. La liaison entre le fichier et l'objet externe

7.3.1. L'établissement de la liaison

Un fichier (logique) peut être vu comme un objet interne au programme. Pour pouvoir effectuer des opérations sur le fichier, il faut qu'il soit relié à un objet externe. Il n'est pas intéressant que cette liaison soit prise en compte par l'éditeur de liens. En effet cela figerait cette liaison au moment de cette édition de liens, le programme exécutable ne pouvant alors s'exécuter que sur des objets externes définis à ce moment. Par ailleurs l'éditeur de liens se préoccupe essentiellement des liaisons internes au programme, alors qu'il s'agit de liaisons externes. Pour les mêmes raisons, il n'est pas judicieux que la liaison soit fixée au moment du chargement du programme. Au contraire elle peut être établie et rompue dynamiquement au cours de son exécution.
Nous reviendrons ultérieurement sur la définition de cette liaison, qui doit permettre d'associer un fichier interne au programme à un objet externe. En supposant que cette définition existe, deux opérations sur un fichier quelconque permettent d'exploiter cette définition:
Les opérations que nous avons indiquées dans les paragraphes précédents ne peuvent être appliquées que sur des fichiers ouverts, puisqu'elles ont pour conséquence des accès à un objet externe qui doit donc avoir été associé au fichier.
Il y a toutefois une exception à cette règle d'établissement dynamique de la liaison. La plupart des systèmes établissent trois liaisons spécifiques préalablement à l'exécution du programme, pour les trois fichiers standards:
SYSIN pour l'entrée des données provenant de l'utilisateur,
SYSOUT pour la sortie des données vers l'utilisateur,
SYSERR pour la sortie des messages d'erreurs vers l'utilisateur.

7.3.2. Représentation interne d'un fichier

La représentation interne d'un fichier logique dans le programme est une structure de données (appelée parfois bloc de contrôle de données ou encore Data Control Bloc). Elle contient quatre types d'informations:
Certaines des informations énoncées ci-dessus sont statiques, c'est-à-dire, connues à la compilation. Ce sont celles qui sont directement liées à la nature du fichier tel que l'utilise le programmeur. La plupart sont en fait dynamiques, car elles dépendent du fichier et de l'objet externe avec lequel il est relié. La figure 7.2 montre une telle représentation d'un fichier logique lorsqu'il est ouvert ou fermé.

Fig. 7.2. Représentation d'un fichier ouvert ou fermé.

7.4. Conclusion

+ Les objets externes peuvent être utilisés pour échanger des informations. Cet échange peut nécessiter de convertir les données dans une représentation commune.
+ Les objets externes peuvent être utilisés pour mémoriser des données à long terme. Aucune conversion n'est nécessaire sauf pour les pointeurs vers la mémoire centrale qui perdent toute signification.
+ Le fichier (logique) est le point de vue qu'a un programme d'un objet externe. On distingue en général le fichier séquentiel d'enregistrements, le fichier séquentiel de texte, et le fichier à accès aléatoire.
+ Un fichier doit être relié à un objet externe pour pouvoir être utilisé. La liaison est établie par l'ouverture, et supprimée par la fermeture.
+ En mémoire centrale, un fichier logique est représenté par une structure de données (DCB) qui contient les attributs de la liaison, le descripteur de l'objet externe, les procédures d'accès et les tampons d'entrées-sorties.


[1] au moins dans le cas des systèmes centralisés. Dans un réseau local, avec un serveur de fichier, ce peut être une autre machine.