Traduction par Jean-luc Biord, du Site de la communauté Qt francophone.
English TOC.

8. Fichiers , Répertoires et Flux

Ce chapitre concerne les fichiers et les actions liés aux fichiers. Il couvrira les parties importantes des classes Qt indépendantes de la plateforme sur les fichiers et le système de fichiers. Après chaque introduction de classe un peu de code réel sera employé pour démontrer l'utilisation des classes.

QFile

Qt manipule les fichiers comme des objets. Par exemple, un fichier est représenté par une instance de la classe QFile. Le fichier n'existant pas, il ne doit pas être ouvert. La méthode exists() est employée pour déterminer si le fichier existe. Si le fichier existe, il peut être supprimé en utilisant la méthode remove(). Pour la lecture et l'écriture (ou tous les deux) le fichier doit être ouvert. C'est fait en utilisant la méthode open(). Un fichier peut-être ouvert en plusieurs modes, voici les plus communs :

En travaillant avec des fichiers de log, c.-à-d. en ajoutant l'information à un fichier, il est indispensable d'ouvrir le fichier avec IO_WriteOnly | IO_Append afin d'ouvrir le fichier en ajout. Quand on l'appellera, la méthode open() renverra TRUE si elle a réussi ou FALSE si le fichier n'a pu être ouvert. Si un quelconque des modes d'écriture (IO_WriteOnly ou IO_ReadWrite) est employé, le fichier est créé s'il n'existe pas.

En traitant des objets fichier, il est parfois utile de savoir si un fichier est ouvert ou pas. C'est fait facilement avec la méthode isOpen() Une fois fini avec un fichier, appelez la méthode close() pour le fermer. Cela vide tous les tampons non encore écris sur le disque. Si on veut vider un cache disque sans fermer le fichier, il faut employer la méthode flush().

L'exemple 8-1 montre comment la classe QFile peut-être employée. L'exemple 8-2 montre une session Bash en utilisant l'application de l'exemple 8-1. La commande touch crée le fichier f.txt tandis que chmod -r enlève l'accès en lecture au fichier.

#include <qapplication.h>
#include <qfile.h>

#include <iostream>

int main( int argc, char **argv )
{
  QApplication a( argc, argv );

  QFile f( "f.txt" );

  if( !f.exists() )
  {
    // It does not exist
    std::cout << "The file does not exist." << std::endl;

    return 0;
  }

  // It exists, open it
  if( !f.open( IO_ReadOnly ) )
  {
    // It could not open
    std::cout << "Failed to open." << std::endl;

    return 0;
  }

  // It opened, now we need to close it
  std::cout << "It worked." << std::endl;

  f.close();

  return 0;
}

Exemple 8-1

$ ./qfile
The file does not exist.
$ touch f.txt
$ ./qfile
It worked.
$ chmod -r f.txt
$ ./qfile
Failed to open.

Exemple 8-2

Flux

Un fichier en lui même n'a pas beaucoup d'utilité. Il a quelques membres de base pour la lecture et l'écriture mais employant une classe de flux pour la lecture et/ou l'écriture réelles, le système devient ainsi plus facile d'emploi et plus flexible.

Pour manipuler l'information texte QTextStream. Pour des données binaires il y a QDataStream, mais ce chapitre se concentrera sur les textes.

Le lecteur curieux pourrait déjà avoir découvert la relation entre la classe de flux QFile et la classe IODevice. Cela signifie que n'importe quel code employant un flux pour lire ou pour écrire, par exemple, un fichier peut également lire des sockets, des bases de données, de la mémoire, etc. Ceci permet de créer du code très flexible et réutilisable.

QTextStream fournit les opérateurs << et >> pour les types communs. Dans le deuxième tutoriel de Trolltech, dans le chapitre Data Elements chapter et la section intitulée "Reading and Writing Data Elements" on démontre comment mettre en application ces opérateurs pour n'importe quelle classe ou structure utilisée.

En utilisant la propriété flags du flux texte le formatage de sortie peut-être contrôlé. Par exemple, la base (binaire, octal, décimal, hexadécimal) des nombres en sortie peut être contrôlée.

En conclusion, la méthode atEnd() renvoie une valeur booléenne indiquant s'il y a encore des données dans la source de données courante.

L'exemple 8-3 montre comment employer un flux de texte en combinaison avec un fichier. L'exemple 8-4 montre une session Bash en utilisant le résultat de l'application . La commande wc -l compte le nombre de lignes dans le fichier indiqué.

#include <qapplication.h>
#include <qfile.h>
#include <qtextstream.h>

#include <iostream>

int main( int argc, char **argv )
{
  QApplication a( argc, argv );

  QFile f( "f.txt" );

  if( !f.open( IO_WriteOnly | IO_Append ) )
  {
    std::cout << "Failed to open file." << std::endl;
    return 0;
  }

  QTextStream ts( &f );

  ts << "This is a test-run." << endl;

  f.close();

  return 0;
}

Exemple 8-3

$ wc -l f.txt
wc: f.txt: No such file or directory
$ ./stream
$ wc -l f.txt
      1 f.txt
$ ./stream
$ wc -l f.txt
      2 f.txt

Exemple 8-4

Chemins de Répertoire

Les différentes plateformes ont différentes manières d'indiquer les chemins. Windows a des lecteurs et des répertoires, comme c:\foo\bar, alors qu'UNIX, et MacOS X qui est un dérivé d'UNIX, emploie une racine simple avec des répertoires, comme /foo/bar. Elles diffèrent de l'un à l'autre également par le caractère utilisé pour séparer les répertoires. Afin de représenter des chemins d'une manière indépendante de la plateforme, Qt fournit la classe QDir.

En explorant un système de fichiers, il est bien d'avoir un point de départ. Dans ce but QDir a un certain nombre de membres statiques. Le premier est current() qui renvoie simplement un QDir représentant le répertoire courant de l'application. Puis, il y a la méthode root() qui renvoie la racine du lecteur courant. Pour des systèmes avec plusieurs lecteurs il y a la méthode drives() qui renvoie un ensemble d'instances de QFileInfo (n'essayez pas d'utiliser delete sur le pointeur retourné, il appartient à Qt). Finalement, la méthode home() pointe vers le répertoire local de l'utilisateur courant.

Se déplacer est possible pour commencer à partir d'une des méthodes statiques mentionnées dans le paragraphe précédent ou depuis une chaîne. Une telle chaîne peut être nettoyée en utilisant la méthode cleanDirPath(). L'existence du chemin peut-être vérifiée en utilisant la méthode exists(). Si un chemin relatif est donné, convertToAbs() le converti en chemin absolu. Pour se déplacer les deux méthodes cd() and cdUp() sont fournies. Le travail est le même qu'avec leurs équivalents cd et cd ... de Bash/Cmd/DOS. Quand la méthode isRoot() renvoie TRUE, il n'y a aucun besoin d'appeler cdUp().

Il peut être utile de se déplacer, mais bien plus utile encore de faire quelque chose. La méthode mkdir() essaye de créer un nouveau répertoire. Elle renvoie TRUE si elle a réussie, autrement FALSE. Les méthodes rmdir() et rename() renvoient également TRUE si elles ont réussies, mais renomme et supprime respectivement des répertoires. rename() peut également renommer des fichiers, mais pour les supprimer la méthode remove() est employée.

En se déplaçant et agissant sur des parties du système de fichiers, il est important de savoir quelles options il a. Avant d'aller plus loin sur la façon de travailler avec le contenu du répertoire courant il y a deux méthodes à voir.

La première est setSorting. Cette méthode rend possible le contrôle de l'ordre d'affichage des entrées. La méthode est contrôlée par un ensemble de drapeaux logiquement combinés par OR. Il y a quatre modes exclusifs qui ne peuvent pas être combinés: QDir::Name, QDir::Time, QDir::Size et Unsorted. En plus de cela, il y a quelques modificateurs pour ignorer des cas, mettre les répertoires en premier, etc... Ils sont détaillés ici.

Enfin, il y a la méthode setFilter. Cette méthode contrôle les entrées qui seront vues en listant le contenu d'un répertoire. Les options sont logiquement combinées par la méthode OR pour former un filtre. Puisqu'il y a ainsi bon nombre d'options, je recommanderais un regard à la documentation officielle.

L'exemple 8-5 montre un exemple d'emploi de QDir. Il liste simplement le contenu de tous les répertoires secondaires du répertoire courant et les affiche à la console.

#include <qapplication.h>
#include <qdir.h>

#include <iostream>

int main( int argc, char **argv )
{
  QApplication a( argc, argv );

  QDir currentDir = QDir::current();

  currentDir.setFilter( QDir::Dirs );
  QStringList entries = currentDir.entryList();
  for( QStringList::ConstIterator entry=entries.begin(); entry!=entries.end(); ++entry )
    std::cout << *entry << std::endl;

  return 0;
}

Exemple 8-5

Notez qu'un QStringList est retourné. Pour accéder à ses membres un ConstIterator est employé. Ceux-ci fonctionnent beaucoup comme leurs équivalents de la STL list<string> et list<string>::const_iterator et ne seront en outre pas exposés ici.

Plus d'informations sur les fichiers et les répertoires

setFilter peut être utile pour trouver les entrées de répertoire qui nous intéresse, mais il y a encore plus d'informations associées à chaque entrée. Au lieu d'utiliser entryList() on peut employer entryInfoList. Elle renvoie une liste d'instances QFileInfo fournissant toute l'information liée à chaque entrée. Une chose intéressante à noter est que la liste retournée par l'appel à entryInfoList appartient ainsi à l'objet QDir et ne peut pas être supprimée. La liste retournée est réutilisée dans les appels suivants des mêmes méthodes, ainsi, si la liste doit être employée plus tard elle doit être copiée.

Quelle information chaque QFileInfo contient-il alors ? D'abord, nous pouvons connaître quel type d'entrée nous avons en employant isDir, isFile et isSymLink. Ces méthodes renvoient une valeur booléenne qui est TRUE si le type de l'entrée passée correspond au type attendu par la méthode.

Il est également intéressant de savoir comment l'entrée est utilisée. À cette fin, il y a pléthore de méthodes. D'abord, le chemin peut-être trouvé en employant filePath(). Le chemin absolu (c.-à-d. non relatif) peut-être obtenu avec absFilePath(). Le nom du fichier peut-être obtenu avec fileName() tandis que le nom de base (sans extension) et l'extension peuvent être trouvés avec baseName() et extension() respectivement. Ce dernier, si l'option booléenne facultative est à TRUE renvoie l'extension complète, par exemple pour le fichier test.tar.gz l'extension complète est tar.gz tandis qu'avec la valeur par défaut c'est gz. En utilisant la méthode dir() une instance de QDir représentant le chemin de l'entrée de répertoire est fournie.

Il est également intéressant de savoir quels sont les attributs d'une entrée. Dans ce but les méthodes renvoyant un booléen, isReadable(), isWriteable(), isExecutable() et isHidden() existent.

Enfin, il y a l'information de datation concernant l'entrée. Elle est accessible par les méthodes created(), lastModified() et lastRead(). Toutes ces méthodes renvoient des instances de QDateTime. Cette classe peut être convertie en objet QString en utilisant la méthode toString().

L'exemple 8-6 démontre comment obtenir un ensemble d'objets QFileInfo d'un objet QDir et comment lister avec lui les entrées.

#include <qapplication.h>
#include <qdir.h>

#include <iostream>

int main( int argc, char **argv )
{
  QApplication a( argc, argv );

  QDir currentDir = QDir::current();
  currentDir.setFilter( QDir::Files );

  const QFileInfoList *infos = currentDir.entryInfoList();
  const QFileInfo *info;

  QFileInfoListIterator infoIt( *infos );
  while( (info=infoIt.current()) != 0 )
  {
    std::cout << "Base name: " << info->baseName( TRUE ) << std::endl;
    std::cout << "Extension: " << info->extension( TRUE ) << std::endl;
    std::cout << "Created: " << info->created().toString() << std::endl;

    ++infoIt;
  } }

Example 8-6

Résumé

Il n'y a pas de code d'exemple pour ce chapitre.

This is a part of digitalfanatics.org and is valid XHTML.