Précédent Index Suivant

Descripteurs de fichier

Au chapitre 3, nous avons vu les fonctions standard du module Pervasives, elles permettent d'accéder aux fichiers via des canaux d'entrées-sorties. Il existe un moyen de plus bas niveau d'accès aux fichiers en ayant recours à leur descripteur.

Un descripteur de fichier est une valeur abstraite, de type Unix.file_descr, qui contient les informations nécessaires à l'utilisation d'un fichier : un pointeur vers ce fichier, les droits d'accès à ce fichier, les conditions d'accès au fichier (lecture ou écriture), la position courante dans le fichier, etc.

Trois descripteurs sont prédéfinis. Ils correspondent aux fichiers d'entrée standard, de sortie standard et d'erreur standard.

# ( Unix.stdin , Unix.stdout , Unix.stderr ) ;;
- : Unix.file_descr * Unix.file_descr * Unix.file_descr =
<abstr>, <abstr>, <abstr>


Attention à ne pas les confondre avec les canaux d'entrées-sorties leur correspondant :

# ( Pervasives.stdin , Pervasives.stdout , Pervasives.stderr ) ;;
- : in_channel * out_channel * out_channel = <abstr>, <abstr>, <abstr>


Des fonctions de conversion entre canaux et descripteurs de fichier sont décrites à la page ??.

Droits d'accès aux fichiers
Sous Unix, des droits en lecture, en écriture et en exécution sont attachés à chaque fichier. Ils concernent trois catégories d'utilisateurs : le propriétaire du fichier, les membres du groupe1 du propriétaire ou l'ensemble de tous les utilisateurs.

Les droits d'un fichier sont représentés par 9 bits divisés en trois groupes de trois bits. Le premier groupe représente les droits du propriétaire, le deuxième les droits des membres du groupe du propriétaire et le dernier les droits des autres utilisateurs. Dans chaque groupe de trois bits, le premier représente le droit en lecture, le deuxième, le droit en écriture et le dernier, le droit en exécution. On a coutume de représenter ces droits respectifs par les lettres r, w et x , et l'absence de droit par un tiret (-). Par exemple, le droit en lecture pour tous et en écriture pour le propriétaire seul s'écrit rw-r--r--. C'est, en fait, l'entier 420 (soit le binaire 0b110100100). On utilisera souvent la notation octale 0o644 qui est d'un emploi plus aisé. Ces droits sur les fichiers ne sont pas utilisés sous Windows.

Manipulation des fichiers

Ouverture d'un fichier
Ouvrir un fichier, c'est récupérer un descripteur de ce fichier. Suivant l'usage que l'on veut en faire, il existe plusieurs modes d'ouverture des fichiers. Chacun correspond à une valeur du type open_flag décrit figure 18.2.

O_RDONLY en lecture
O_WRONLY en écriture
O_RDWR en lecture et en écriture
O_NONBLOCK ouverture dans un mode non bloquant
O_APPEND en ajout à la fin du fichier
O_CREAT crée le fichier s'il n'existe pas
O_TRUNC remet le fichier à 0 s'il existe
O_EXCL échoue si le fichier existe

Figure 18.2 : Valeurs de type open_flag


Ces modes peuvent être combinés, en conséquence la fonction openfile prendra en argument une liste de valeurs de type open_flag.

# Unix.openfile ;;
- : string -> Unix.open_flag list -> Unix.file_perm -> Unix.file_descr =
<fun>
Le premier argument est le nom du fichier et le dernier est un entier2 codant les permissions à donner au fichier en cas de création.

Voici comment ouvrir en lecture un fichier, ou le créer avec les droits rw-r--r-- s'il n'existe pas :

# let fichier = Unix.openfile "essai.dat" [Unix.O_RDWR; Unix.O_CREAT] 0o644 ;;
val fichier : Unix.file_descr = <abstr>
Fermeture d'un fichier
La fonction Unix.close permet de fermer un fichier. On l'applique au descripteur du fichier que l'on désire fermer.

# Unix.close ;;
- : Unix.file_descr -> unit = <fun>
# Unix.close fichier ;;
- : unit = ()
Redirection de fichiers
On peut attacher à une même entrée-sortie plusieurs descripteurs. Si l'on dispose d'un seul descripteur et que l'on veut en obtenir un nouveau, on utilisera :

# Unix.dup ;;
- : Unix.file_descr -> Unix.file_descr = <fun>


Si l'on dispose de deux descripteurs et que l'on veut réassigner au second l'entrée-sortie correspondant au premier, on utilisera la fonction :

# Unix.dup2 ;;
- : Unix.file_descr -> Unix.file_descr -> unit = <fun>


Par exemple, on redirige la sortie d'erreur sur un fichier :

# let sortie_erreur = Unix.openfile "err.log" [Unix.O_WRONLY;Unix.O_CREAT] 0o644 ;;
val sortie_erreur : Unix.file_descr = <abstr>
# Unix.dup2 Unix.stderr sortie_erreur ;;
- : unit = ()
Les écritures sur la sortie erreur standard sont détournées vers le fichier err.log.

Entrées-sorties sur un fichier

Les fonctions de lecture et d'écriture sur un fichier Unix.read et Unix.write utilisent une chaîne de caractères comme média entre le fichier et le programme Objective CAML.

# Unix.read ;;
- : Unix.file_descr -> string -> int -> int -> int = <fun>
# Unix.write ;;
- : Unix.file_descr -> string -> int -> int -> int = <fun>


Outre le descripteur de fichier et la chaîne, les fonctions prennent deux entiers en argument qui sont l'indice du premier caractère et le nombre souhaité de caractères à lire ou à écrire. L'entier retourné est le nombre de caractères effectivement lus ou écrits.

# let mode = [Unix.O_WRONLY;Unix.O_CREAT;Unix.O_TRUNC] in
let fic = Unix.openfile "fichier" mode 0o644 in
let str = "012345678901234565789" in
let n = Unix.write fic str 4 5
in Printf.printf "On a écrit %s dans le fichier\n" (String.sub str 4 n) ;
Unix.close fic ;;
On a écrit 45678 dans le fichier
- : unit = ()


La lecture procède du même principe :

# let fic = Unix.openfile "fichier" [Unix.O_RDONLY] 0o644 in
let str = String.make 20 '.' in
let n = Unix.read fic str 2 10 in
Printf.printf "On n'a lu que %d caractères" n;
Printf.printf " et on obtient la chaîne %s\n" str;
Unix.close fic ;;
On n'a lu que 5 caractères et on obtient la chaîne ..45678.............
- : unit = ()


Un accès à un fichier se fait toujours à la position courante contenue dans son descripteur. On peut cependant modifier cette position grâce à la fonction :

# Unix.lseek ;;
- : Unix.file_descr -> int -> Unix.seek_command -> int = <fun>


Le premier argument est le descripteur du fichier, le second est la taille, en caractères, du déplacement et le troisième argument, de type Unix.seek_command, indique l'origine. Ce dernier argument a trois valeurs possibles : Une position erronée provoque soit le déclenchement d'une exception, soit une valeur de retour égale à 0 suivant les fonctions d'entrées-sorties utilisées.

Canal d'entrée-sortie
Le module Unix fournit des fonctions de conversion entre les descripteurs de fichier et les canaux d'entrées-sorties du module Pervasives :

# Unix.in_channel_of_descr ;;
- : Unix.file_descr -> in_channel = <fun>
# Unix.out_channel_of_descr ;;
- : Unix.file_descr -> out_channel = <fun>
# Unix.descr_of_in_channel ;;
- : in_channel -> Unix.file_descr = <fun>
# Unix.descr_of_out_channel ;;
- : out_channel -> Unix.file_descr = <fun>


Il est nécessaire de préciser si les canaux d'entrées-sorties obtenus par conversion transfèrent des données binaires ou des caractères :

# set_binary_mode_in ;;
- : in_channel -> bool -> unit = <fun>
# set_binary_mode_out ;;
- : out_channel -> bool -> unit = <fun>


Dans l'exemple suivant on crée un fichier en utilisant les fonctions du module Unix et on le lit en utilisant la fonction d'ouverture du module Unix et la fonction d'entrée de plus haut niveau input_line.

# let mode = [Unix.O_WRONLY;Unix.O_CREAT;Unix.O_TRUNC] in
let f = Unix.openfile "fichier" mode 0o666 in
let s = "0123456789\n0123456789\n" in
let n = Unix.write f s 0 (String.length s)
in Unix.close f ;;
- : unit = ()
# let f = Unix.openfile "fichier" [Unix.O_RDONLY;Unix.O_NONBLOCK] 0 in
let c = Unix.in_channel_of_descr f in
let s = input_line c
in print_string s ;
close_in c ;;
0123456789- : unit = ()


Disponibilité
Un programme peut avoir à gérer une multiplicité d'entrées-sorties. Or celles-ci ne sont pas toujours disponibles : d'autres programmes ont pu précédemment en réclamer l'usage. La fonction suivante permet de connaître la liste des entrées-sorties disponibles à un moment donné parmi une liste donnée :

# Unix.select ;;
- : Unix.file_descr list ->
Unix.file_descr list ->
Unix.file_descr list ->
float ->
Unix.file_descr list * Unix.file_descr list * Unix.file_descr list
= <fun>
Les trois premiers arguments représentent les listes respectivement des entrées (lecture), des sorties (écriture) et des sorties en erreur. Le dernier argument indique un délai d'attente en secondes (une valeur négative indique un délai nul). Le résultat est la liste des entrées-sorties disponibles en lecture, écriture et erreur.

Warning


select n'est pas implantée pour Windows



Précédent Index Suivant