Section courante

A propos

Section administrative du site

Fichiers

Cette page aborde les problèmes de programmation en relation avec les fichiers et Turbo Pascal. Voici les différents problèmes abordés :



Fonctionnalité pour le Turbo Pascal inférieur ou égal à 3

Il est possible de changer un attribut de fichier de caché à non caché comme avec SetFAttr dans les anciennes versions de Turbo Pascal. Pour y arriver, il faut utiliser directement l'interruption 21, fonction 43h, Sous-Fonction 00h et l'interruption 21, fonction 43h, Sous-Fonction 01h. Voici les routines permettant d'y arriver :

  1. Procedure GetFAttr(FName:String;Var RdOnly,Hid,Sys,Arch:Boolean);
  2. Var 
  3.  R:Registers;
  4. Begin
  5.  FillChar(R,Sizeof(R),0);
  6.  FName:=FName+#0; { Configuré comme une chaîne de caractères terminée par un caractère nul pour DOS }
  7.  With R Do begin
  8.   AH:=$43;
  9.   AL:=0;
  10.   DS:=Seg(FName); 
  11.   DX:=Ofs(FName)+1; { Sauter la longueur du Pascal d'octet }
  12.   MsDos(R);
  13.   RdOnly:=(CL and $01)>0;
  14.   Hid:=(CL and $02)>0;
  15.   Sys:=(CL and $04)>0;
  16.   Arch:=(CL and $20)>0;
  17.  End; 
  18. End; 
  19.  
  20. Procedure PutFAttr(FName:String;RdOnly,Hid,Sys,Arch:Boolean);
  21. Var 
  22.  R:Registers;
  23. Begin
  24.  FillChar(R,Sizeof(R),0);
  25.  FName := FName+#0; { Configuré comme une chaîne de caractères terminée par un caractère nul pour DOS }
  26.  With R Do begin
  27.   AH:=$43; 
  28.   AL:=1;
  29.   DS:=Seg(FName); 
  30.   DX:=Ofs(FName)+1; { Sauter la longueur du Pascal d'octet }
  31.   If RdOnly Then CL := CL or $01;
  32.   If Hid Then CL := CL or $02;
  33.   If Sys Then CL := CL or $04;
  34.   If Arch Then CL := CL or $20;
  35.   MsDos(R);
  36.  End;
  37. End;

Il existe également des bibliothèques, comme par exemple l'unité HANDLELB.PAS de la bibliothèque HDLLIB-TP, permettant de manipuler fichiers du système d'exploitation DOS, sans passer par les routines prédéfinies du Turbo Pascal.

Fonctionnalité pour le Turbo Pascal 4 ou supérieur

Les Turbo Pascal 4 ou supérieur, offre un unité nommé DOS, offrant des routines supplémentaire pour manipuler des fichiers. Ainsi, par exemple, on peut changer la date, l'heure et l'attribut d'un fichier en utilisant des procédure de l'unité DOS. Voici un exemple d'un programme permettant de modifier ses 3 éléments à la fois :

  1. Program ChangeTimeAndAttribut;
  2.  
  3. Uses Dos;
  4.  
  5. Var
  6.  F:File;
  7.  Attr:Word;
  8.  Time:LongInt;
  9.  DT:DateTime;
  10.  
  11. BEGIN
  12.  Assign(F,'FILENAME.EXT');
  13.  DT.Year:=93;
  14.  DT.Month:=1;
  15.  DT.Day:=1;
  16.  DT.Hour:=1;
  17.  DT.Min:=0;
  18.  DT.Sec:=0;
  19.  Packtime(dt,Time);
  20.  Attr:=ReadOnly;
  21.  SetFTime(F,Time);
  22.  SetFAttr(F,Attr);
  23. END.

Grâce à la procédure SetFAttr, on peut par exemple créer un clone de la commande chmod de Linux comme le montre l'exemple CHMOD du projet LINUX-0.

Manipulation des noms de fichiers

Le Turbo Pascal offre de puissantes routines de manipulation de chaînes de caractères, lesquelles peuvent être exploitées en complément de la gestion des fichiers. Par exemple, si vous souhaitez supprimer le point et tous les caractères le suivant dans un nom de fichier DOS valide, procédez comme suit :

  1. FileName:='MONFICH.TXT';
  2. Name:=Copy(FileName,1,Pos('.',FileName)-1);

Vous obtiendrez le nom du fichier, soit 'MONFICH'. Sinon, vous pouvez utiliser FSplit pour décomposer toutes les différentes parties d'un nom de fichier/chemin et l'obtenir de cette façon.

Détection de l'existence d'un fichier

Il existe plusieurs façons de détecter la présence d'un fichier en utilisant les fonctions existantes de l'unité DOS, en voici quelques unes :

  1. Function FileExists(FileName:String):Boolean;
  2. Var
  3.  Rec:SearchRec;
  4. Begin
  5.  FindFirst(FileName,AnyFile,Rec);
  6.  FileExists:=(DOSError=0);
  7. End;

ou

  1. Function FileExists(FileName:String):Boolean;Begin
  2.  FileExists:=(FSearch(FileName,'')<>'')
  3. End;

ou

  1. Function FileExists(FileName:String):Boolean;
  2. Var
  3.  DirInfo:SearchRec;
  4. Begin
  5.  FindFirst(FileName,AnyFile,DirInfo);
  6.  If(DOSError=0)Then FileExists:=True
  7.                Else FileExists:=False;
  8. End;

ou finalement une technique uniquement compatible avec la marque Turbo Pascal en mode réel (Interruption 21h, Fonction 43h, Sous-fonction 00h) :

  1. Function FileExists(Filename:String):Boolean;Assembler;ASM
  2.  PUSH DS
  3.   LDS SI,[FileName] { Fabrique un ASCIIZ }
  4.   XOR AH,AH
  5.   LODSB
  6.   XCHG AX,BX
  7.   MOV Byte Ptr [SI+BX],0
  8.   MOV DX,SI
  9.   MOV AX,4300h      { Demande les attributs de fichier }
  10.   INT 21h
  11.   MOV AL,False
  12.   JC  @1            { Échec ? }
  13.   INC AX
  14. @1:
  15.  POP DS
  16. END;

Partage de fichiers

Lorsque vous partagez des fichiers simultanément, par exemple via un multitâche ou un réseau, il est nécessaire d'utiliser le partage de fichiers fourni par la commande SHARE du DOS ou fourni par un interpréteur de commande réseau (dans Novell, le partage de fichiers est pris en charge par l'interpréteur de commande réseau sur les serveurs, et non localement.

Le partage de fichiers est simple dans Turbo Pascal ou Borland Pascal, car la variable système FileMode définit dans quel mode un certain fichier est ouvert :

  1. Const
  2.  fmReadOnly  = $00;  (* *)
  3.  fmWriteOnly = $01;  (* Un seul d'entre eux doit être utilisé *)
  4.  fmReadWrite = $02;  (* *)
  5.  
  6.  fmDenyAll   = $10;  (* Avec seulement un de ceux-ci *)
  7.  fmDenyWrite = $20;  (* *)
  8.  fmDenyRead  = $30;  (* *)
  9.  fmDenyNone  = $40;  (* *)
  10.  
  11.  fmNoInherit = $70;  (* Définir pour «Pas d'héritage» *)

La construction de la variable FileMode est simple, il suffit d'ajouter les valeurs appropriées de la façon suivante :

  1. FileMode:=fmReadOnly+fmDenyNone;
  2.       (* Ouvrir le fichier en lecture seule, autoriser la lecture et l'écriture. *)
  3.  
  4. FileMode:=fmReadWrite+fmDenyWrite;
  5.       (* Ouvrir le fichier pour la lecture et l'écriture, refuser l'écriture. *)
  6.  
  7. FileMode:=fmReadWrite+fmDenyAll;
  8.       (* Ouvrir le fichier pour la lecture et l'écriture, refuser tout. *)

Supposons que vous ouvriez le fichier avec «fmReadWrite+fmDenyWrite». Cela vous permettra de lire et d'écrire librement dans le fichier, tandis que d'autres processus pourront lire librement le fichier. Si un autre processus tente d'ouvrir le fichier pour l'écriture, ce processus recevra l'erreur «Accès refusé» ou «Access denied».

Noter que fmNoInherit est rarement utilisé - il définit si un processus enfant généré par votre processus pourra utiliser le descripteur de fichier fourni par votre processus.

La variable FileMode n'est utilisée que lorsque le fichier est ouvert :

  1.  { ... }
  2. Assign(F,FileName);
  3. FileMode:=fmReadOnly+fmDenyNone;
  4. Reset(F);
  5. FileMode:=Whatever;    (* La modification du mode de fichier ici n'affecte pas les fichiers déjà ouverts *)

Par défaut, FileMode est défini comme FileMode:=$02 dans Turbo Pascal ou Borland Pascal, ce qui est appelé «Mode de compatibilité» dans la documentation Turbo Pascal ou Borland Pascal. Deux processus accédant au même fichier avec ce mode de fichier entraînent l'erreur critique «Violation de partage».

Ouvrir plus de 20 fichiers simultanément

Il existe une façon d'accéder à plus de 20 fichiers ouvert simultanément avec Turbo Pascal 7.0 en mode réel. Car à l'origine, le DOS avait une limitation n'autorisant pas plus de 15 fichiers ouverts simultanément. C'est la même chose que ce que vous avez dans le fichier CONFIG.SYS après la ligne Files=Write, il ne peut gérer que 15 fichiers ouverts. Voici une unité pour contourner le problème en allouant un tampon mémoire pour les fichiers ouvert à côté du PSP du programme. Il est important de noter que l'unité de l'exemple suivant devrait être inclus en premier, il ne peut pas être en recouvrement ou entrée dans un CONFIG.SYS :

  1. Unit MaxFiles;
  2.  
  3. INTERFACE
  4.  
  5. Const
  6.  MaxFile = 255; { pour 250 fichiers ouverts}
  7. Var
  8.  Index:Integer;
  9.  FilesHandleBuffer:Array[1..MaxFile] of Byte;
  10.  
  11. BEGIN
  12.  For Index:=1 to MaxFile do FilesHandleBuffer[Index]:=$FF;
  13.  For Index:=1 to 5 do FilesHandleBuffer[index]:=Mem[PrefixSeg:$18+Pred(Index)];
  14.  MemW[PrefixSeg:$32]:=MaxFile;
  15.  MemW[PrefixSeg:$34]:=Ofs(FilesHandleBuffer);
  16.  MemW[PrefixSeg:$36]:=Seg(FilesHandleBuffer);
  17. END.

Est-ce un fichier

On peut aussi vérifier grâce à l'unité DOS si le fichier indiqué est vraiment un fichier et non pas un répertoire. Voici un fonction permettant de vérifier s'il s'agit bien d'un fichier :

  1. Function IsFile(sFile:String):Boolean;
  2. Var 
  3.  S:SearchRec;
  4. Begin
  5.  FindFirst(sFile,Directory,S);
  6.  IsFile:=(DOSError=0)and(s.Attr and Directory<>Directory)and(Pos( '?',sFile) = 0)and(Pos('*',sFile)=0);
  7. End;

Nom avec des caractères générique

Dans certaines situations, il est important de savoir si l'on a affaire à un seul fichier ou à plusieurs fichiers en même temps. Lorsqu'il s'agit de plusieurs fichiers, on les appelle des fichiers avec des caractères génériques (ou un caractère joker en anglais). L'astuce consiste à repérer soit un point d'interrogation (« ? ») soit un astérisque (« * »). Voici une fonction permettant de vérifier si le nom est unique :

  1. Function IsWildCard(Const Path:String):Boolean;Begin
  2.  IsWildCard:=(Pos('*',Path)>0)or(Pos('?',Path)>0);
  3. End;

Copie de fichier binaire

Le Turbo Pascal n'offre pas de fonction de copie d'un fichier binaire complet de façon intégré. Pour y parvenir, nous devons donc ouvrir un fichier, puis créer un fichier, copier les données d'un fichier vers l'autre et fermer les deux fichiers. Cette opération ressemblerait donc à ceci :

  1. Function CopyFile(Source,Target:String;ShowProgression:Boolean):Boolean;
  2. Var
  3.  SourceFile,TargetFile:File;
  4.  RecordsRead:Integer;
  5.  Buffer:Array[1..1000]of Byte;
  6. Begin
  7.  CopyFile:=False;
  8.  Assign(SourceFile,Source);
  9.  {$I-}Reset(SourceFile,1);{$I+}
  10.  If IOResult<>0Then Begin
  11.   WriteLn('Fichier source introuvable ',Source);
  12.   Exit;
  13.  End;
  14.  Assign(TargetFile,Target);
  15.  {$I-}Rewrite(TargetFile,1);
  16.  BlockRead(SourceFile,Buffer,SizeOf(Buffer),RecordsRead);
  17.  While RecordsRead>0 do Begin
  18.   BlockWrite(TargetFile,Buffer,RecordsRead);
  19.   BlockRead(SourceFile,Buffer,SizeOf(Buffer),RecordsRead);
  20.  End;
  21.  Close(SourceFile);
  22.  Close(TargetFile);
  23.  {$I+}
  24.  CopyFile:=True;
  25. End;

Renommer un fichier

En Turbo Pascal, le renommage d'un fichier est un peu spéciale, dans le sens, qu'il faut ouvrir un fichier pour pouvoir le renommer. Cette philosophie est un peu à l'opposer du système d'exploitation DOS, lequel ne permet pas ce genre d'opération lorsqu'un fichier est ouvert. Ainsi, pour pouvoir renommer un fichier en Turbo Pascal, on devrait avoir une fonction ressemblant à ceci :

  1. Function RenameFile(Source,Target:String):Boolean;
  2. Var
  3.  F:File;
  4. Begin
  5.  {$I-}Assign(F,Source);
  6.  Rename(F,Target); {$I+}
  7.  RenameFile:=IoResult=0;
  8. End; 


Dernière mise à jour : Jeudi, le 8 juillet 2024