|
LES FICHIERS ET DELPHI
Dans delphi il existe diverses méthodes de lecture de fichier. Si
vous êtes débutant vous avez dû procéder comme moi pendant longtemps en ajoutant
un memo invisible dans votre form car vous connaissiez par cœur les commandes
loadfromfile et savetofile de ce composant puis vous avez été face à un problème, le memo il ne lit pas correctement mes fichiers, le memo il est limité
en taille de caractères, le memo il est vraiment nul.
Mais non le memo il est pas nul c'est juste qu'il n'a jamais été
conçu pour ouvrir et fermer les fichiers, non le memo il ne sert qu'à afficher du
texte et si il faut, servir de bloc-notes avec une limite de caractère comme
notepad dans Windows.
Alors là, vous vous êtes peut-être dit : mais comment on lit un
fichier?
1.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 .
Et 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. A vous de choisir.
Après cette petite explication nous allons passer au plus
intéressant, comment qu'on fait ?
2.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.
3.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 :
var
F:textfile;
puis on lui assignera le fichier.
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 :
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.
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 :
var
F:textfile;
lig : string;
i:integer;//qui nous servira plus tard
begin
if savedialog.execute then
assignfile(F,savedialog.filename) //là 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 :
rewrite(F);
ou suivant votre choix :
if fileexists(savedialog.filename) then
append(F)
else
rewrite(F);//car sinon erreur
puis :
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.
4.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 :
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;
pas de problème, je pense, donc passons à l'écriture :
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 .
5. lecture / écriture par paquet
Voilà la partie la plus difficile de mon tutorial 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 :
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 ?
Et 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é !!).
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 :
A 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 :
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 :
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 :
repeat on répète
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 ;
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 à
ecrit le nombre d'octets réellement écrit;
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 ecrit <> lut donc
tant qu'ecrit 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
ecrit : cette dernière partie de
blockread et blockwrite est facultative donc si vous n'en avez pas besoin vous
pouvez l'omettre.
6.D'autres outils pour la gestion de vos fichiers et quelques
trucs en plus
É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é.
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 si 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.
7.Conclusion
C'est fini il ne vous reste plus qu'à télécharger les exemples
de ce tutorial si vous en avez besoin et si vous avez des problèmes des
critiques ou autre chose voici mon mail, bodman@createur.org.
|