I. Comment on lit un fichier ?

Pour lire un fichier, il faut déjà savoir de quel genre de fichier il s'agit : texte, suite d'octet ou groupe de variable. Puis sa taille, environs 2 ko ou plus voir beaucoup plus et même moins.

Là vous saurez quelle méthode choisir, la lecture linéaire, la lecture par octet (par variable) ou la lecture par paquet.

Voilà une description rapide de ces trois types de lecture :

Imaginons un livre

On peut le lire de plusieurs manières :

  • ligne par ligne ;
  • lettre par lettre ;
  • chapitre par chapitre.

Eh bien les fichiers c'est pareil :

  • ligne par ligne ;
  • octet par octet ;
  • paquet par paquet.

La vraie différence réside dans la vitesse de la lecture / écriture : bloc par bloc c'est plus rapide que octet par octet.

Il y a aussi l'optimisation, car si vous voulez lire un fichier de configuration, vous préférez peut-être le lire ligne par ligne plutôt que par octet, à moins que vous ne préfériez par variable. À vous de choisir.

Après cette petite explication nous allons passer au plus intéressant, comment qu'on fait ?

II. La sécurité

Oui avant toute chose voici une partie très importante lorsque l'on veut utiliser les fichiers, la sécurité.

Il y a plusieurs systèmes, vous aurez le choix entre laisser le programme s'occuper des exceptions ou le contraire (le plus sage pour éviter les plantages).

Voilà la méthode :

{$I+} active la vérification des erreurs et {$I-} la désactive ; vous pouvez faire appel à ceci n'importe ou dans votre code.

A chaque erreur si vous avez fait appel à {$I+} une exception EInOutError est déclenchée.

III. La lecture / écriture linéaire

Cette méthode est la première que j'ai apprise et me semble aussi la plus simple.

Pour lire un fichier, tout d'abord il faut utiliser une variable qui contiendra son nom.

Pour le cas d'une lecture linéaire on considérera que ce fichier sera de type texte.

donc pour commencer on le déclarera comme variable :

 
Sélectionnez
var
F:textfile;

Ppuis on lui assignera le fichier.

 
Sélectionnez
if opendialog.execute then
assignfile(F,opendialog.filename);

Là on a utilisé un opendialog pour trouver le fichier et être sûr de son existence.

Ensuite on va aller au début du fichier, l'initialiser :

 
Sélectionnez
reset(F);

C'est tout.

ensuite passe la lecture proprement dite. Mais on ajoutera une variable string pour contenir nos lignes lors du transfert, ainsi qu'un élément memo pour contenir notre texte.

 
Sélectionnez
while not eof(F) do begin //cette boucle répètera la lecture d'une ligne tant que nous n'aurons pas atteint la fin du document EOF
readln(F,lig);//à chaque fois que l'on utilisera readln on passera à la ligne suivante.
memo.lines.add(lig); // ajoute notre ligne au memo
end;
closefile(F);//cette procédure ferme notre fichier F

Bon voilà c'est tout pour la lecture linéaire, maintenant l'écriture.

Pour l'écriture on reprend le code précédent mais avec quelques modifications :

 
Sélectionnez
var
F:textfile;
lig : string;
i:integer;//qui nous servira plus tard
begin
if savedialog.execute then
assignfile(F,savedialog.filename) // rien ne change même si l'on utilise un savedialog

C'est là que tout change : là on ne va pas utiliser reset() car on ne veut pas préparer le fichier à la lecture mais on a le choix entre deux procédures, rewrite() qui va supprimer le fichier F s'il existe et réécrire par-dessus mais on peut aussi utiliser append() qui ajoutera tout au fichier F et gardera ainsi les données existantes(Attention avec append s'il n'y a pas de fichier de ce nom il y aura une erreur).

donc on reprendra notre boucle sauf qu'ici ce sera :

 
Sélectionnez
rewrite(F);

Ou suivant votre choix :

 
Sélectionnez
if fileexists(savedialog.filename) then
append(F)
else
rewrite(F);//car sinon erreur

Puis :

 
Sélectionnez
for I := 1 to memo.lines.count do begin
lig := memo.lines[I];
writeln(F,lig) // ici pas le choix;
end;
closefile(F);

Et voilà là j'ai créé une boucle qui lira chaque ligne du memo et l'ajoutera au fichier.

IV. Lecture / écriture par octet ( ou variable )

Là c'est un peu plus compliqué mais attention pas plus dur, je m'explique. Vous aurez à peu près les mêmes méthodes mais vous devrez tout de même choisir le type de fichier car ce ne sera pas un textfile donc vous pourrez choisir un file of char, file of integer ou file of je sais pas quoi c'est à vous de décider.

Donc voilà l'exemple :

 
Sélectionnez
var
F:file of char; // j'ai choisi char mais à vous de choisir
carac:char;
begin
if opendialog.execute then
assignfile(F,opendialog.filename);
reset(F);
while not eof(F) do begin
read(F,carac);//là, plus de readln mais un read tout court qui envoie dans notre char nommé carac un char qui vient de notre file of char nommé F
memo.lines.text :=memo.lines.text+carac;//on ajoute au memo chaque char
end;
closefile(f);
end;

Ppas de problème, je pense, donc passons à l'écriture :

 
Sélectionnez
var
F : file of integer;
B: array[1..6] of integer;
I : integer;
begin
for I := 1 to 6 do
B[I] := random(1000);
if savedialog.Execute then
begin
assignfile(F,savedialog.filename);
rewrite(F);
for I := 1 to 6 do
write(F,B[I]);
closefile(F);
end;

Commentaire : Ici j'ai changé de type de fichier( que je suis sournois !). Cette fois-ci ce sont des chiffres aléatoires entre 0 et 1000 qui seront ajoutés au fichier. Vous pourrez regarder le fichier, vous serez surpris-je pense, car les chiffre seront marqués en hexadécimal, ce qui donne un truc assez abstrait dans un bloc-notes, mais ne vous inquiétez pas, dans un éditeur hexadécimal avec une calculette vous pourrez vous assurer que vos chiffres on été bien interprétés.

Nous avons initialisé un fichier typé integer (file of integer) avec la valeur donnée avec notre dialogue de sauvegarde (savedialog) puis on l'a initialisé pour l'écriture, ensuite avec une boucle qui tournera autant de fois qu'il y a de chiffres à donner on écrira le chiffre de position I qui se trouve, puis à la fin de la boucle on ferme le fichier.

V. Lecture / écriture par paquet

Voilà la partie la plus difficile de mon tutoriel, car assez libre dans l'ensemble.

Bon on va y aller doucement, car ce serait bête de devoir tout relire.

Alors voilà, comme toute lecture (oui on va commencer par la lecture ) on va assigner le fichier à F notre variable file préférée :

 
Sélectionnez
var
F:file; // Ah oui c'est bon on est arrivé dans la cours des grands, maintenant ce sont des fichiers purs que l'on utilise et pas des fichiers de quelque chose.
Buf: array[1..1024] of Char;//on verra plus tard
lus : integer; //idem
begin
if opendialog.execute then
assignfile(f,opendialog.filename);//laà c'est pas dur
reset(F,1);

Oh zut c'est quoi ce truc après F , ce 1 qui chamboule toutes les habitudes, c'est quoi ?

Eh bien c'est la taille d'enregistrement lors d'un transfert. Cette valeur n'est à fournir que pour des fichiers non typés (file tout court, ce qui est le cas en ce moment). Je vous conseille de mettre 1, car c'est une valeur universelle (aucun fichier n'est encore à virgule, pour l'instant lol) en plus si vous ne mettez rien ce sera 128 par défaut et si vous mettez autre chose vous devez être sûr que cette valeur marche sinon plantage général sur votre machine (j'ai testé !!).

 
Sélectionnez
repeat
BlockRead(F, Buf, SizeOf(Buf),lut);
memo1.lines.text := memo1.lines.text + buf;
until lus =0;
closefile(F);

Bon ici vous allez apprendre une nouvelle fonction blockread et vous allez comprendre à quoi notre buffer (c'est le nom que l'on donne à une variable qui sert à stoker des données) nommé buf sert.

On a une boucle (comme d'habitude) qui lit un bloc et le met dans buf puis l'ajoute au memo.

Donc blockread il fonctionne comme cela :

blockread(variable de fichier, là où on met ce qu'on lit, on donne nombre de chose qu'on va lire, renvoie ce qui a été réellement lu)

Petite explication :

À chaque tour de la boucle, on lit 1024 octets du fichier puis on les ajoute au memo. S'il y en a moins de 1024 à lire on rendra le reste là c'est la fonction blockread qui s'en chargera. Par contre, si ce qui a été réellement lu est 0, alors on arrête la boucle de lecture et on ferme.

Maintenant passons à l'enregistrement :

Pour l'exemple nous allons garder celui de la lecture sauf que cette fois-ci nous n'utiliserons pas un memo mais nous créerons un nouveau fichier.

Donc l'exemple précédent était :

 
Sélectionnez
var
F:file;
lut : integer;
Buf: array[1..024] of Char;
begin
if opendialog.execute then
assignfile(F,opendialog.filename);
reset(F,1);
repeat
BlockRead(F, Buf, SizeOf(Buf),lut);
memo.lines.text := memo.lines.text + buf;
until lus =0;

closefile(F);

Et notre nouvelle version est :

 
Sélectionnez
var
F, F2: file;
lus,ecrit:integer;
Buf: array[1..1024] of Char;
begin
if OpenDialog.Execute then
if SaveDialog.Execute then
begin

AssignFile(F, OpenDialog.FileName);
Reset(F, 1);
AssignFile(F2, SaveDialog.FileName);
Rewrite(F2, 1);

repeat
BlockRead(F, Buf, SizeOf(Buf), lus);
BlockWrite(F2, Buf, lus, ecrit);
until (lut = 0) or (ecrit <> lus )
CloseFile(F);
CloseFile(F2);
end;
end;

Là on utilise un opendialog et un savedialog pour être sûr de l'existence des deux fichiers puis on les ouvre et on les initialise ( vous avez remarqué que reset avait une option facultative et que rewrite a la même).

Ensuite une boucle apparaît, elle décrit la lecture et l'écriture. Là nous allons nous arrêter pour faire quelque chose que j'aime bien, car c'est pour moi un très bon moyen de comprendre, c'est la traduction du code :

 
Sélectionnez
repeat

On répète :

 
Sélectionnez
BlockRead(F, Buf, SizeOf(Buf), lut);

Bloc de 1024 octet ( taille de buf ) à envoyer sur buf depuis F, assigner à lus le nombre d'octet réellement lus :

 
Sélectionnez
BlockWrite(F2, Buf, lut, ecrit);

Bloc de lus octets (dont le nombre d'octets est égal au nombre lus lors de la lecture juste au-dessus) à envoyer sur F depuis buf, assigner à écrit le nombre d'octets réellement écrit;

 
Sélectionnez
until (lus = 0) or (ecrit <> lut )

Et on répète cela tant qu'il n'y a pas lut = 0 donc tant qu'on lit quelque chose ou alors tant qu'il n'y a pas écrit <> lut donc tant qu'écrit et lut sont égaux (tant qu'il n'y a pas de problèmes, car ce serait un problème si l'on écrivait plus ou moins que ce que l'on a lu.)

Cette seconde condition est plus là comme sécurité qu'autre chose.

Et bien sûr pour finir, on ferme les fichiers.

Petit truc au sujet de lus et écrit : cette dernière partie de blockread et blockwrite est facultative donc si vous n'en avez pas besoin vous pouvez l'omettre.

VI. D'autres outils pour la gestion de vos fichiers et quelques trucs en plus

VI-A. Écrire a la fin d'un fichier lors d'un enregistrement par variables ou par paquets

Comme vous l'avez vu append ne marche que pour les fichiers de type textfile donc voici une méthode pour la réaliser : déjà pour écrire on peut aussi utiliser reset() cela ne supprimera pas le fichier mais mettra le curseur au début du fichier conséquence si l'on écrit tout sera mis par-dessus, par contre si on met le curseur à la fin du fichier tout sera ajouté.

 
Sélectionnez
reset(F);
seek(F,filesize(F));

fileexists(fiche); fonction boolean qui renvoie l'existence du fichier dont le chemin d'accès est fiche.

deletefile(fiche); efface le fichier fiche.

Attention ces procédures réclament l'ouverture du fichier avec les procédures que vous venez d'apprendre ( reset() …).

Erase(F); efface le fichier F ouvert.

FilePos(F); donne la position du curseur dans le fichier F.

FileSize(F); taille du fichier F qui n'est pas de type texte.

Ioresult boolean qui s'il est false indique une erreur

rename(F, nouveau); renomme le fichier F en nouveau

truncate(F); supprime tout ce qui ce trouve après le pointeur du fichier F

seek(F,t); ramène à la position t (t est un longint)du fichier F.

VII. Conclusion

C'est fini il ne vous reste plus qu'à télécharger les exemples de ce tutoriel si vous en avez besoin et si vous avez des problèmes des critiques ou autre chose voici mon mail, bodman@createur.org.