:: Enseignements :: Licence :: L2 :: 2008-2009 :: Système ::
[LOGO]

Entrées/Sorties


Le but de ce TP est d'utiliser les principales fonctions de manipulation d'entrées sorties en C de la bibliothèque standard afin d'illustrer les notions de tampons d'entrées / sorties.

Exercice 1 - Rappels de Shell

Tout processus (programme) possède trois canaux standards stdin, stdout et stderr. La commande shell A < f exécute la commande A avec stdin ouvert sur le fichier f. Symétriquement, A > f exécute A avec stdout ouvert sur le fichier f. Enfin A | B exécute les deux programmes A et B en parallèle, le canal stdout de A étant redirigé sur le canal stdin de B.

Noter que les commandes <f et >f sont utilisables simultanément. Enfin 2>f redirige stderr au lieu de stdout.

Essayez l'effet de ces commandes avec la commande ls, par exemple. Attention de ne pas effacer de fichiers importants ! La redirection écrase les fichiers sans préavis!

Exercice 2 - Copie élémentaire

On commence ce TD par mettre en place un environnement de travail propre :
  • créez un nouveau répertoire ;
  • téléchargez le fichier copy1.c ;
  • écrivez un Makefile pour compiler copy1.c en un programme copy1.

Essayez par exemple
copy1 < foo
avec un fichier texte foo arbitraire.

Exercice 3 - Effet des Tampons

Pour pouvoir expérimenter l'efficacité des tampons de fichiers, nous voulons :
  • mesurer le temps d'exécution des lectures/écritures ;
  • faire des mesures sur des fichiers de tailles variables.

  1. Mesures de Temps : Modifier le programme copy1.c pour qu'il imprime sur stderr le temps d'exécution de la boucle principale (man 2 times, voir aussi le cours : benchmark). Le temps qui nous interesse est le temps total user+system.
  2. Fichiers de Tailles Variables : Ecrire un programme gen.c qui prend un entier n sur la ligne de commande et affiche n caractères sur sa sortie standard. Faites en sorte que gen imprime aussi son temps d'exécution sur stderr, par exemple GEN:456.
  3. Tampons de Tailles Variables : Faire man setvbuf, voir aussi le cours 6. Modifiez le programme copy1.c pour qu'il prenne des entiers p et q sur la ligne de commande et qu'il affecte :
    • un tampon de taille p sur stdin
    • un tampon de taille q sur stdout
    On conservera l'impression du temps d'exécution sur la sortie d'erreur. Essayez plusieurs valeurs pour n, p, q dans l'exemple suivant:
    gen n | copy1 p q > logout
  4. Simuler un tampon : Ecrire la fonction Myprintf, qui écrit la chaine de caractère dans un tampon et le vide à l'aide de la fonction MyFlush (qui affiche le contenu du buffer sur la sortie standard). Ces fonctions prendront en argument un pointeur sur un fichier, correspondant à l'output. Si l'output est modifié lors d'un nouvel appel à la fonction Myprintf, on vide le buffer.

Exercice 4 - Le programme head

La commande head n imprime les n premières lignes de stdin sur stdout. Une ligne se termine par '\n'.
  • Réécrire cette commande avec un programme C ;
  • Ecrire un programme genline similaire à gen mais qui écrit des lignes plutôt que des caractères. Par exemple genline n pourra écrire n fois la ligne Bonjour.
  • Testez vos programmes avec des commandes du type : genline p | head q
  • Observez lorsque p>q et p<q.

On va maintenant oberver l'impact de head sur genline :
  • Modifiez genline n pour qu'il imprime sur stderr les lignes "ligne numero i" avec i de 1 à n au fur et à mesure de sa génération.
  • Est-ce que head q modifie le moment où se termine genline p ?

On peut confirmer ou pousser cette observation plus loin:
  • Ecrire un programme neverdie.c qui imprime indéfiniment la ligne Bonjour (on l'arrête avec Ctrl-C).
  • Testez neverdie | head 5

Exercice 5 - Le programme sort

Ce programme lit toutes les lignes de stdin, les range dans un tableau, puis ré-imprime ces lignes sur stdout dans l'ordre alphabétique.

Réécrire cette commande en utilisant une bibliothèque de tri standard (man qsort). Il faut procéder comme suit:
  • allouer un tableau pour stocker les lignes avec malloc ;
  • allouer un buffer pour stocker une ligne avec malloc ;
  • lire N caractères depuis stdin dans le buffer (man fread) ;
  • chercher la fin de ligne ; si elle n'est pas trouvée, augmenter la taille du buffer (man realloc) et lire N' caractères supplémentaires ;
  • faire une copie de la ligne (man strdup ou man strcpy) dans le tableau des lignes ; Eventuellement, agrandir le tableau des lignes si nécessaire ;
  • une fois la dernière ligne lue, trier le tableau (man qsort) ;
  • imprimer le tableau final sur stdout.

Exercice 6 - Le programme tail

La commande tail n f imprime les n dernières lignes du fichier f sur stdout. C'est beaucoup plus difficile que pour head ou sort car il ne faut surtout pas charger tout le fichier en mémoire. Utilisez fopen pour ouvrir le fichier.

On fait une lecture du fichier par petits blocs avec la commandes fseek et fread (man!), en commençant par la fin du fichier. Il faut accumuler ces blocs de données (man realloc, man strcpy) jusqu'à trouver les n dernières lignes.

Attention au cas de la dernière ligne!

Peut-on faire la même chose avec stdin au lieu du nom de fichier f ?