Stocker des chaînes de caractères dans des flux de données

Les flux de données sont des classes descendantes de TStream. Les plus utilisés permettent d'accéder aux fichiers (TFileStream), à un buffer en mémoire (TMemoryStream) mais aussi aux chaînes de caractères (TStringStream).

Le principe d'utilisation est assez simple : on crée une instance du flux, on lit ou écrit des données dedans puis on supprime l'instance.

Là où ça se complique un peu c'est quand on écrit des données de tailles et de types différents. Dans ce cas il faut spécifier la taille sur les deux opérations, comme on le faisait dans le temps sur les fichiers binaires avec blockread() et blockwrite().

L'avantage des flux c'est qu'on peut manipuler de tout sans se préoccuper de l'endroit où c'est physiquement stocké (en mémoire ou sur disque).

Sur les types basiques (nombres, booléens) ou les tableaux (selon ce qu'ils contiennent) il est facile d'avoir la taille avec la fonction sizeof().

Sur les chaînes de caractères ça se complique car le nombre de caractères de la chaîne ne correspond que rarement au nombre d'octets qu'elle occupe à cause (ou grâce) aux encodages. Si on fait un sizeof() on se retrouvera en fait avec la taille occupée par la variable en tant que pointeur vers la zone en mémoire où se trouve la chaîne, non la taille occupée par la chaîne elle-même.
Exception à cela : les chaînes ANSI en tant que tableau Pascal historique.

Delphi le gère très bien en interne, mais ne propose pour le moment rien pour mettre une chaine dans autre chose qu'un TStringStream. Charge au développeur de mélanger ça avec un string en mémoire ou en fichier.

Comme il m'arrive assez régulièrement d'utiliser des flux de stockage de données de types différents et que j'y stocke aussi des chaînes, j'ai ajouté l'unité Olf.RTL.Streams.pas à ma librairie d'utilitaires. Elle contient ce qu'il faut pour enregistrer et charger une chaîne dans n'importe quel flux où se trouverait autre chose qu'une chaîne.

Le principe est simple : je passe par un TStringStream pour connaître la taille physique de la chaîne et l'enregistre avant les octets de la chaîne. Ca permet de lire uniquement ces informations dans le flux final lorsqu'on recharge les données.

A l'utilisation ça donne simplement ça pour l'écriture

  s:=tmemorystream.create;
  try
    SaveStringToStream(edit1.Text, s);
  finally
    s.free;
  end;

et ça pour la lecture :

  s:=tmemorystream.create;
  try
    Edit1.Text := LoadStringFromStream(s);
  finally
    s.free;
  end;

Ca évite de recopier plusieurs fois le bloc de code de lecture et d'écriture selon nos cas.

Si vous voulez voir ça en action, consultez les méthodes LoadFromStream() et SaveToStream() dans les code source des unités uConfig.pas ou Zicplay.Types.pas du projet Zicplay.


Liens associés

Ces liens s'ouvrent dans la même fenêtre que cette page. En cliquant dessus vous quitterez Les trucs et astuces d'un développeur Pascal.
Pensez à les ouvrir dans un nouvel onglet si vous préférez rester ici pour y revenir plus facilement.


Mug Toucan DX dans la baie de RioMug Toucan DX dans la baie de Rio