• Aucun résultat trouvé

Généralités et terminologie

du format de saisie. En revanche, lorsque la quantité des données d’entrée devient importante, il est souvent plus efficace de les saisir dans un fichier avec toutes les possibilités d’un éditeur, puis de faire lire ce fichier par le programme.

5.2 Généralités et terminologie

Dans les échanges de données plus massifs qu’avec le terminal, ou avec des fichiers dont le format peut être imposé par d’autres applications, il est souvent nécessaire de préciser les règles de conversion en entrée ou en sortie grâce à une spécification de format.

INTEGER :: k

INTEGER, DIMENSION(100) :: ti ! tableau de 100 entiers REAL, DIMENSION(100) :: tr ! tableau de 100 réels

OPEN(9, FILE=’donnees.dat’) ! ouverture du fichier => connecté à l’unité 9 DO k = 1, 100

READ(9, ’(i4, f9.5)’) ti(k), tr(k) ! lecture d’un enregistrement END DO

CLOSE(9) ! fermeture du fichier

Dans cet exemple, chaque instruction READ lit dans le fichier donnees.dat un enregistrement constitué d’un entier codé sur 4 chiffres, suivi d’un réel sur 9 caractères dont 5 après le point décimal. La chaîne de caractèresi4, f9.5constitue le format de lecture. L’objectif de ce chapitre est de décrire les différentes instructions permettant les échanges de données et d’introduire la syntaxe des spécificateurs de format.

5.2.1 Fichiers externes et fichiers internes

Fichiers externes

Outre les entrées–sorties standard qui s’opèrent via le terminal, fortran peut contrôler plusieurs flux de données en lecture ou en écriture associés à des fichiers externes (external files), hébergés

5.2. GÉNÉRALITÉS ET TERMINOLOGIE 33

par des périphériques (disquettes, disques, bandes magnétiques, CD, ...).

Ces fichiers externes doivent être connectés à des unités logiques (logical unit) à l’aide de l’ins-truction OPEN. L’instructionCLOSE permet de fermer le fichier et donc de libérer l’unité logique préalablement connectée. Une unité logique est désignée par un entier positif ou nul.

L’entier désignant l’unité logique peut être choisi entre 0 et une limite supérieure dépendant du processeur3,4,5.

Unités logiques standard

Mais les unités logiques standard d’entrée et de sortie sont préconnectées par défaut, et peuvent être désignées par le symbole*.

Sousunix, l’entrée standard (clavier) et la sortie standard (écran) sont traditonnellement pré-connectées respectivement aux unités logiques 5 et 6. La sortie d’erreur standard est préconnectée par défaut à l’unité logique 0 ; pour écrire sur la sortie d’erreur, il suffirait donc de préciser le numéro d’unité logique 0.

Mais depuis fortran 2003, le module intrinsèque ISO_FORTRAN_ENV (cf. 5.3.1, p. 36) définit plusieurs constantes nommées caractérisant l’environnement, dont les numéros des unités logiques

standard :input_unit, output_unitet error_unit, qui permettent donc de désigner ces unités ⇐f2003 logiques de façon portable.

Fichiers internes

À l’opposé des fichiers externes stockés sur un dispositif périphérique, on parle aussi d’écriture et de lecture sur des fichiers internes (internal files)cf. 8.4.3 p. 89lorsque l’on code des données numériques sous forme de chaînes de caractères (écriture) ou inversement que l’on décode des chaînes de caractères représentant des données (lecture). Les fichiers internes ne sont que de simples variables de type chaîne de caractères, explicitement déclarées dans le programme et stockées en mémoire vive. Ils sont notamment utilisés pour générer des formats variables pour des opérations d’entrées-sorties (cf.5.4.5, p.45).

5.2.2 Notion d’enregistrement

Unenregistrement(record) est la généralisation à un fichier de la notion de ligne sur un terminal.

Un fichier est une suite d’enregistrements.

Lors d’une opération d’entrée-sortie sur un fichier en accès séquentiel, chaque instruction de lecture ou d’écriture provoque par défaut6le passage à l’enregistrement suivant.

5.2.3 Fichiers formatés et fichiers non formatés

Les données numériques peuvent être stockées dans des fichiers :

– soit sous la forme de chaînes de caractères (qui seront bien sûr eux-mêmes codés en binaire) : les fichiers sont dits alorsformatés ou codés (formatted). Les entrées-sorties standard s’effec-tuent sous forme codée.

– soit directement sous la forme binaire utilisée pour le stockage dans la mémoire de la machine : les fichiers sont dits alorsnon-formatés (unformatted).

Ainsi, lors des entrées-sorties formatées de données numériques sur des fichiers externes, les instructions d’écriture ou de lecture déclenchent en réalité successivement deux opérations : une conversion7selon les règles définies par unformatet un transfert de données vers un périphérique.

Plus précisément, suivant qu’il s’agisse d’entrée ou de sortie formatée, elle signifiera :

3. La limite supérieure est bien souvent celle des entiers par défaut : soit 231−1 sur processeur 32 bits et 2631 sur processeur 64 bits avec le compilateurg95; mais elle reste de 2311 avec le compilateurxlfd’ibm.

4. Certaines bibliothèques se réservent l’usage d’une plagefixede numéros d’unités logiques, qui ne sont plus, en conséquence, disponibles pour les programmes de l’utilisateur de ses bibliothèques.

5. La lecture ou l’écriture sur une unité logiquen non connectée force la connexion implicite à un fichier externe dont le nom par défaut estfort.n sousunix.

6. Il est possible, en fortran 90, de faire exception à cette règle grâce à l’optionADVANCE=no.

7. Dans le cas d’un fichier interne, c’est la seule opération déclenchée par l’instruction d’entrée-sortie.

– soit d’abord une lecture de chaînes de caractères, puis une conversion en représentation interne ;

– soit d’abord une conversion de la représentation interne en chaînes de caractères, puis une écriture de chaînes de caractères.

Si la conversion provoque une erreur à l’exécution, c’est l’ensemble de l’instruction qui échoue, ce qui s’avère particulièrement gênant par exemple pour les entrées interactives, en cas de faute de frappe. Pour fiabiliser les saisies au clavier, on est amené à exploiter les codes de retour deREAD8. La lecture s’effectue alors dans une boucle qui ne s’arrête que lorsqu’il n’y a plus d’erreur.

1 PROGRAM robust_lect

2 IMPLICIT NONE

3 INTEGER :: i=-100, ok

4 WRITE(*,*) ’entrer un entier’

5 DO

6 READ(*, *, iostat=ok) i

7 IF(ok==0) EXIT

8 WRITE(*,*) ’erreur: recommencez’

9 END DO

10 WRITE(*,*) ’i=’, i

11 END PROGRAM robust_lect

Choix entre fichier formaté ou non-formaté

Le choix entre les deux types de fichiers pour stocker des données numériques est dicté par les critères suivants :

non-formatés : pas de conversion, donc transfert plus rapide et sans perte de précision, fi-chiers plus compacts ; mais fifi-chiers non portables9 et difficiles à lire par d’autres outils10; en particulier, dans les fichiers binaires en accès séquentiel, fortran écrit et s’attend à lire, en tête et en fin (c’est moins gênant) de chaque enregistrement, une balise d’enregistrement (record marker), sous forme d’un entier11 indiquant le nombre d’octets de l’enregistrement : il faut en tenir compte si on accède au fichier au travers de programmes utilisant d’autres langages ;

formatés : lisibilité par d’autres outils (filtres ou simples éditeurs de texte), portabilité entre applications et entre machines ; mais fichiers plus volumineux et accès plus lent ; perte de précision possible.

5.2.4 Méthodes d’accès aux données

On distingue deux méthodes d’accès aux enregistrements stockés dans des fichiers :

8. Cela impose d’utiliser la deuxième syntaxe, plus complète, deREAD,cf.5.3.4, p.39.

9. Les données numériques sur plusieurs octets peuvent être enregistrées en mémoire de deux façons, selon l’ordre choisi entre les octets qui représentent la valeur en binaire :

– dans l’ordre des poids décroissants (octets de poids fort au début) : on parle d’orientationbig-endian ou gros-boutiste.

– dans l’ordre des poids croissants (octets de poids faible au début) : on parle d’orientationlittle-endian ou petit-boutiste.

Si la majorité les processeurs de PC, en particulier lesx86ont adopté l’orientationlitte-endian, les processeurs de serveursibm , lesPowerPC et les ia64 notamment sont d’orientation big-endian. On notera que ces différences peuvent concerner les entiers, mais aussi les flottants, car la norme IEEE 754 (cf.annexeC, page140) ne spécifie pas l’orientation des octets, et les caractères multi-octets d’unicode (UTF-16 et UTF-32).

10. Sousunix, la commandeod(octal dump) permet d’afficher sous diverses formes le contenu binaire d’un fichier.

Elle permet entre autres d’afficher un aperçu du contenu de fichiers binaires grâce à une ou plusieurs options-tqui spécifient comment interpréter les octets (nombre d’octets à grouper et conversion suivant un type), par exemple :

od -t d4pour des entiers en décimal sur 4 octets (32 bits) ; od -t f4ouod -t fFpour des réels sur 4 octets (32 bits) ;

od -t f8ouod -t fDpour des réels en double précision sur 8 octets (64 bits).

11. Cet entier peut être codé sur 64 bits sur les processeurs 64 bits.

5.2. GÉNÉRALITÉS ET TERMINOLOGIE 35

– l’accès séquentiel (sequential), où les enregistrements sont stockés les uns à la suite des autres12 et où, pour accéder à un enregistrement particulier, il est nécessaire de lire tous les enregistrements précédents ; dans ce mode, il n’est pas possible de modifier un enregistre-ment sans compromettre l’intégrité de tous les suivants ;

– l’accèsdirect (direct), où les enregistrements sont repérés par un numéro qui permet (moyen-nant la connaissance de la taille, nécessairement fixe, des enregistrements) de calculer la position de l’enregistrement dans le fichier et d’accéder ainsi à un enregistrement particulier (y compris en écriture) sans lire explicitement ceux qui le précèdent, ni affecter les suivants (cf.5.6, p.48).

Le fortran 2003 a introduit une troisième méthode inspirée du langage C, l’accèsstream ouflot, ⇐f2003 combinant des avantages des deux précédents. Le positionnement dans le fichier se fait en

spéci-fiant le numéro d’unités de stockage (en général des octets) en commençant à 1 en début de fichier.

Les fichiers formattés en accès stream ont aussi une structure d’enregistrement, mais les fins d’en-registrement doivent être explicitement spécifiées en écrivant le caractère fourni par la fonction intrinsèqueNEW_LINE13.

Choix entre accès direct et accès séquentiel

Le choix entre les méthodes d’accès aux données dépend de leur nature (qui peut déterminer la taille des enregistrements), de leur volume (stockable facilement ou non dans des tableaux en mémoire) et de l’usage qu’on leur prévoit. Ce choix est parfois imposé par les contraintes suivantes :

– les enregistrements d’un fichier à accès direct sont nécessairement de taille fixe ;

– seul l’accès direct permet d’écrire un enregistrement sans avoir à réécrire la totalité du fichier.

Ainsi, les fichiers de bases de données, dont les enregistrements doivent pouvoir être mis à jour de façon individuelle, et dont le volume ne permet pas un stockage facile en mémoire vive, sont stockés dans des fichiers à accès direct.

Parfois, alors que les deux méthodes sont envisageables, des considérations de performances (même en lecture seule) peuvent amener à préférer l’accès direct, si par exemple on doit très souvent accéder à des données non contigües, de façon aléatoire. Supposons par exemple qu’une fonction soit échantillonnée dans le plan au sein d’un fichier selon une grille en coordonnées rectangulaires et que l’on souhaite la rééchantillonner selon des coordonnées polaires ; lorsque l’on calculera les valeurs de la fonction en suivant un cercle, on devra accéder à des données certainement non contigües dans le fichier initial, qu’il sera donc préférable de lire en accès direct ; il sera donc préférable de créer le fichier initial en accès direct.

5.2.5 Notion de liste d’entrée-sortie

Dans une instruction d’entrée-sortie, les informations échangées sont spécifiées par une liste d’entrée-sortie (i/o-list), qui est une liste d’expressions pour une instruction d’écriture, mais doit être une liste de variables pour une instruction de lecture. Si un élément de la liste est un tableau, il est équivalent à la liste des éléments du tableau14; s’il s’agit d’une structure, elle doit être inter-prétée comme la liste des champs de la structure. Enfin, la liste d’entrée-sortie peut comporter des boucles implicites(aussi utilisées comme constructeurs de tableau,cf.7.1.3, p.72), éventuellement imbriquées.

Dans l’exemple suivant, chacune des trois instructions affiche le tableautde la même façon sur une ligne.

INTEGER, DIMENSION(3) :: t = (/ 1, 2, 3 /) ! tableau initialisé INTEGER :: i

WRITE(*, ’(3i4)’) t ! affichage global

12. Comme sur une bande magnétique qui est un support physique à accès séquentiel.

13. La fonction intrinsèqueNEW_LINEprend pour argument un caractère quelconque et rend le caractère de fin de ligne de même sous-type. C’est l’équivalent du\ndu langage C.

14. Le tableau est transformé en liste en faisant varier d’abord le premier indice, puis le deuxième, ... (cf.7.1.2, p.71).

WRITE(*, ’(3i4)’) t(1), t(2), t(3) ! liste exhaustive WRITE(*, ’(3i4)’) (t(i), i=1, 3) ! boucle implicite