Section courante

A propos

Section administrative du site

Fichiers binaires

Un fichier binaire contient des données de programme entreposées sur le disque. Chaque élément d'un fichier binaire est entreposé dans la même représentation binaire utilisée par un programme QuickPascal. Les fichiers binaires offrent un entreposage optimal des nombres, des booléens et des types énumérés. Par exemple, pour entreposer l'entier 21 000 dans un fichier texte, vous écrivez une chaîne de caractères d'au moins cinq caractères sur le disque. Pour entreposer le nombre dans un fichier binaire, vous n'écrivez que deux octets. Cependant, vous ne pouvez pas afficher directement un fichier binaire ou le visualiser avec un traitement de texte.

Vous accédez à chaque fichier binaire en tant que fichier typé ou non typé :

Fichiers typés

Comme un tableau, un fichier typé est une série de composantes ayant tous le même type. Contrairement à un tableau, un fichier typé n'a pas de taille définie. Un fichier commence à la longueur zéro et s'agrandit automatiquement au fur et à mesure que vous ajoutez des données. De plus, les fichiers servent d'enregistrements permanents existant après la fin du programme.

Essentiellement, les fichiers typés sont des fichiers de données formatés. Le format est déterminé par le type de composante, que vous devez choisir avec soin pour résoudre une tâche de programmation donnée. Par exemple, pour implémenter un système de réservation de compagnie aérienne, vous configureriez un type d'enregistrement pour entreposer toutes les données nécessaires pour une réservation. Ensuite, vous pouvez créer un fichier composé de ces enregistrements. Chaque programme du système doit utiliser ce même type d'enregistrement pour lire correctement le fichier.

La structure d'un fichier typé prend en charge l'accès aléatoire. Par exemple, dans un fichier d'enregistrements, vous pouvez accéder directement à l'enregistrement 367 sans avoir à parcourir les 366 premiers.

Déclaration de fichiers typés

Sans surprise, la syntaxe pour définir un fichier typé est similaire à celle des tableaux :

FILE OF ComponentType

Dans l'affichage de syntaxe ci-dessus, ComponentType peut être n'importe quel type de données valide, avec une restriction : le type de composante ne peut pas être un type de fichier ou un type contenant un type de fichier. Ainsi, les fichiers de tableaux sont légaux, tout comme les tableaux de fichiers. Cependant, un fichier de tableaux de fichiers est illégal.

Le type de composante est souvent un enregistrement. (En fait, d'autres langages de programmation utilisent souvent le terme «enregistrement» pour désigner un composante d'un fichier.) Par exemple, vous pouvez définir un type d'enregistrement pour contenir le nom et le numéro de téléphone d'une personne. Pour créer une liste permanente de numéros de téléphone pour de nombreuses personnes, vous pouvez créer un fichier composé de ces enregistrements.

Le code suivant montre des exemples de types de fichiers valides :

  1. Type
  2.  phonerec=Record
  3.   name:String[20];
  4.   long_distance:Boolean;
  5.   phone:LongInt;
  6.  End;
  7.  
  8.  phone_list=File of phonerec;
  9.  math_file=File of array[1..10] of Real;
  10.  
  11. Var
  12.  master_list:Array[1..20] of phone_list;
  13.  celebs:phone_list;
  14.  lucky_numbers:File of Integer;

Accéder aux données dans un fichier typé

Après avoir déclaré une variable de fichier, vous pouvez l'assigner à un fichier de disque physique avec la procédure Assign, comme décrit dans la page Fichiers texte. Ensuite, vous pouvez ouvrir le fichier en écriture (avec Rewrite) ou à la fois en lecture et en écriture (avec Reset).

Par exemple, le code suivant déclare un fichier d'entiers, affecte la variable file au fichier disque MYFILE.DAT (dans le répertoire racine de l'unité de disque C:), puis ouvre le fichier en lecture et en écriture :

  1. Var
  2.  intfile:File of Integer;
  3.  
  4. BEGIN
  5.  Assign(intfile,'C:\MYFILE.DAT');
  6.  Reset(intfile);

Après avoir ouvert le fichier, vous pouvez lire et écrire n'importe quel nombre de composants de manière séquentielle avec les procédures de lecture et d'écriture. (La section suivante montre comment utiliser l'accès aléatoire.) Ces procédures fonctionnent à la fois avec des fichiers texte et des fichiers typés, et utilisent la même syntaxe dans les deux cas. Mais avec les fichiers typés, chaque élément que vous lisez ou écrivez doit être une variable du type composante.

Par exemple, si int_file est un fichier d'entiers et que a, b et c sont des variables entières, vous pouvez lire ou écrire le fichier comme suit :

  1. Write(int_file,a,b,c); { Écrivez a, b, c dans le fichier }
  2. Read(int_file,n); { Lire l'entier suivant dans le fichier }

Les procédures de lecture et d'écriture n'effectuent aucune mise en forme du texte lorsqu'elles sont utilisées avec des fichiers typés. Dans l'exemple ci-dessus, les procédures lisent et écrivent la valeur numérique des entiers directement vers et depuis le disque. Si int_file était un fichier texte, la procédure Read traduirait les nombres en chaînes de caractères avant de les écrire.

Lorsque vous lisez les composantes d'un fichier, utilisez la fonction Eof ou la fonction FileSize (décrite ci-dessous) pour vous assurer de ne pas lire au-delà de la fin du fichier. La fonction Eof renvoie True si la dernière opération de lecture vous a conduit au-delà de la fin du fichier.

Vous pouvez utiliser un certain nombre d'autres procédures avec des fichiers typés, y compris les procédures répertoriées dans le tableau suivant de la page Fichiers texte. De plus, vous pouvez utiliser ceux listés ci-dessous :

Fonction/Procédure Description
FilePos Prend une variable de fichier comme paramètre et renvoie la position actuelle du fichier (en termes de composantes ou de blocs).
FileSize Prend une variable de fichier comme paramètre et renvoie la taille du fichier en octets ; le résultat a le type LongInt.
Seek Prend une variable de fichier et un entier long comme paramètres, et déplace la position du fichier vers le composant ou le bloc désigné par l'entier
Truncate Prend une variable de fichier comme paramètre et tronque le fichier à la position actuelle du fichier.

Les procédures FilePos et Seek vous permettent de traiter un fichier binaire comme un fichier à accès aléatoire, et la section suivante fournit plus de détails sur la façon de les utiliser. Notez que vous n'êtes pas obligé de traiter un fichier typé comme un fichier strictement séquentiel ou à accès aléatoire. Vous pouvez utiliser n'importe quelle combinaison de fonctions prises en charge pour le type de fichier.

Utilisation de l'accès aléatoire

Vous pouvez utiliser des procédures d'accès aléatoire avec n'importe quel fichier typé. «L'accès aléatoire» est la capacité de lire ou d'écrire des composants à n'importe quel endroit du fichier et dans n'importe quel ordre.

L'accès aléatoire, c'est comme passer un appel téléphonique. Vous pouvez vous connecter immédiatement à n'importe quel endroit du système en donnant le bon numéro. L'accès séquentiel, c'est comme lire un roman. Vous avancez d'une page à l'autre dans l'ordre indiqué.

Les deux principales procédures d'accès aléatoire sont Seek et FilePos. La procédure Seek définit le tampon de fichier sur la composante désigné par le numéro que vous spécifiez. La première composante est noté 0, le second par 1,... La syntaxe est :

Seek(FileVar, Position)

dans laquelle FileVar est une variable de fichier et Position est une constante ou une variable de type LongInt. Par exemple :

  1. Type
  2.  phone_rec=Record
  3.   name,
  4.   notes:String;
  5.   number:LongInt;
  6.  End;
  7.  
  8. Var
  9.  phone_list:File of phone_rec;
  10.  rec10,rec11,recl5,rec25:phone_rec;
  11.  
  12. BEGIN
  13.  Assign(phone_list,'FONEHOME.DAT');
  14.  Reset(phone_list);
  15.  Seek(phone_list,9); { Obtenez les 10e et 11e enregistrements }
  16.  Read(phone_list,rec10,rec11);
  17.  Seek(phone_list,14); { Obtenez le 15e enregistrement }
  18.  Read(phone_list,rec15);
  19.  Seek(phone_list,24); { Obtenez le 25e enregistrement }
  20.  Read(phone_list,rec25);
  21.    { : }
  22. END.

L'exemple ci-dessus copie les enregistrements à des emplacements prédéfinis dans le fichier. Le plus souvent, une application pratique détermine le numéro d'enregistrement de manière interactive. Par exemple, le code suivant demande à l'utilisateur le numéro d'enregistrement et les données, puis entre ces données dans le fichier :

  1. Var
  2.  phone_list:File of phone_rec;
  3.  temp_rec:phone_rec;
  4.  n:LongInt;
  5.  
  6. BEGIN
  7.  Assign(phone_list,'FONEHOME.DAT');
  8.  Reset(phone_list);
  9.  Write('Saisissez le numéro d''enregistrement : ');
  10.  Readln(n);
  11.  Write('Entrez le nom : '); { Prompt pour les données }
  12.  Readln(temp_rec.name);
  13.  Write('Entrer un nombre : ');
  14.  Readln(temp_rec.number);
  15.  Seek(phone_list,n); { Enregistrement d'accès demandé }
  16.  Write(phone_list,temp_rec); { Écrire des données dans un fichier }
  17.   { : }
  18. END.

La fonction FilePos prend une variable de fichier comme paramètre et renvoie le numéro (encore une fois, un LongInt) de la composante actuel.

La fonction Eof est utile pour les opérations d'accès séquentiel et d'accès aléatoire. Cette fonction prend une variable de fichier comme paramètre et renvoie True si la composante actuel est au-delà de la fin du fichier. Ainsi, il vous indique quand vous avez lu jusqu'à la fin du fichier ou avez un numéro d'enregistrement correspondant à une composante de fichier inexistant.

Jusqu'à présent, vous avez vu comment lire et écraser des fichiers existants. Vous pouvez ajouter la fin des fichiers avec :

  1. Seek(f,FilePos(f))

et réécrire complètement les fichiers avec la procédure de réécriture. Mais il n'y a pas de moyen facile d'insérer de nouveaux composantes au milieu d'un fichier. La seule façon d'insérer un composant est de lire un fichier entier en mémoire, de manipuler le contenu et d'écrire à nouveau le fichier sur le disque.

Fichiers non typés

Les variables de fichier non typées prennent en charge les opérations d'entrées/sorties directes de bas niveau avec n'importe quel fichier. Les fonctions BlockRead et BlockWrite utilisées avec des fichiers non typés permettent un transfert de données rapide pour la copie et la sauvegarde des fichiers. Vous pouvez également utiliser des entrées/sorties de fichiers non typés pour créer des fichiers binaires séquentiels avec des enregistrements de longueur variable.

Les fichiers non typés diffèrent des fichiers typés en ce que :

Pour déclarer un type ou une variable en tant que fichier non typé, utilisez simplement le mot-clef FILE. Par exemple :

  1. Type
  2.  low_level=File;
  3.  
  4. Var
  5.  my_file:low_level;

Les procédures Read et Write, prises en charge pour une utilisation avec des fichiers texte et des fichiers typés, ne sont pas prises en charge avec des fichiers non typés. (Sinon, toute procédure prise en charge pour les fichiers typés est également prise en charge pour les fichiers non typés.) Utilisez plutôt les procédures BlockRead et BlockWrite pour accéder aux données. Les procédures BlockRead et BlockWrite lisent et écrivent des enregistrements dans un fichier. Dans ce contexte, "enregistrement" désigne un bloc de données d'une taille spécifique. La taille de bloc par défaut est de 128 octets si vous utilisez la séquence d'ouverture de fichier standard :

  1. Assign(file_var,'FILE');
  2. Reset(file_var);

Avec la taille de bloc par défaut, la procédure BlockRead lit en unités de 128 octets à la fois. Si le dernier BlockRead trouve moins de 128 octets, une erreur se produit. Il est rare que le contenu d'un fichier soit exactement égal à 128*n. Pour éviter les erreurs, vous avez deux alternatives :

Les procédures Reset et Rewrite ont un paramètre facultatif pour définir le nombre d'octets dans un enregistrement. Une fois la taille d'enregistrement définie sur un octet, les procédures BlockRead et BlockWrite transfèrent des multiples d'un octet à chaque exécution. Aucune erreur ne se produit à la fin du fichier.

La syntaxe de BlockRead est :

BlockRead(FileVar, Buffer, Count [, NumRead])

BlockRead lit les enregistrements Count (ou le nombre d'enregistrements restants, selon le moins élevé) du fichier dans Buffer. Le paramètre Buffer peut être n'importe quelle variable suffisamment grande pour contenir le nombre d'octets lus. Le nombre réel d'enregistrements complets lus est renvoyé dans le paramètre facultatif NumRead. Utilisez NumRead pour déterminer si BlockRead a réussi. Si le paramètre NumRead est omis et que BlockRead lit moins d'enregistrements Count, une erreur d'entrée/sortie se produit. La liste des paramètres de BlockWrite est la même que celle de BlockRead.

Le programme simple suivant, DUPLICAT.PAS, illustre une utilisation typique des entrées/sorties de bloc pour copier un fichier :

  1. Program duplicat;
  2.  
  3. Const
  4.  max_buf=16384;
  5. Var
  6.  file_name,copyfile_name:String;
  7.  source,target:File;
  8.  buffer:Array[1..max_buf] of Char; { Tampon de 16 Ko }
  9.  bytes_read,bytes_written:Word;
  10.  
  11. BEGIN
  12.  Write('Entrer la source file_name -> ');
  13.  ReadLn(file_name);
  14.  Write('Entrer le nom du fichier destinataire -> ');
  15.  ReadLn(Copyfile_name);
  16.  Assign(Source,file_name);
  17.  Reset(Source,1); { Taille de 1 octet-bloc }
  18.  Assign(Target, copyfile_name);
  19.  Rewrite(Target,1); { Taille de 1 octet-bloc }
  20.  Repeat
  21.   BlockRead(source,buffer,SizeOf(buffer),bytes_read);
  22.   BlockWrite(target,buffer,bytes_read,bytes_written)
  23.  Until (bytes_read = 0)or(bytes_read <> bytes_written);
  24.  Close(Source);
  25.  Close(Target);
  26. END.

Le programme détecte la fin du fichier en recherchant l'une des deux conditions suivantes :

Les techniques d'entrée/sortie de bloc présentées dans le programme ci-dessus sont utilisées pour implémenter une version étendue de la commande COPY de DOS dans l'exemple de programme EXCOPY.PAS, disponible en ligne dans QuickPascal. Les autres composantes du programme exemple sont les paramètres de ligne de commande ; les routines FindFirst et FindNext ; un arbre binaire pour détecter les noms de fichiers en double ; Vérification des erreurs d'entrée/sortie utilisée avec BlockRead et BlockWrite ; et une sortie d'écran informant l'utilisateur de la progression de la copie du fichier.

La procédure copyfile de EXCOPY.PAS a pour tâche de copier les fichiers, un à la fois. Notez les aspects suivants de la procédure :

Pour exécuter EXCOPY.EXE, compilez d'abord le programme EXCOPY.PAS. Le répertoire courant doit contenir les fichiers source que vous souhaitez copier. Entrez les paramètres de la ligne de commande comme :

EXCOPY TargetDirectory [FileList]

Le paramètre FileList peut contenir un ou plusieurs noms de fichiers séparés par des espaces. Chaque nom de fichier peut contenir les caractères génériques «*» et «?». Si vous omettez FileList, EXCOPY utilise la spécification de fichier par défaut «*.*» comme liste de fichiers.



Dernière mise à jour : Dimanche, le 28 août 2022