u_c_direct_access_variable_file - John COLIBRI. | - mots clé:utilitaire - gestion de fichier
- logiciel utilisé: Windows 98, Delphi 5.0
- matériel utilisé: Pentium 500Mhz, 128 M de mémoire
- champ d'application: Delphi 1 à 6 sur Windows, Kylix
- niveau: débutant en Pascal et Delphi
- uses: u_c_basic_file, u_c_variable_file, u_c_display,
(u_c_basic_object, u_c_file_name, u_loaded, u_dir,
u_c_log, u_strings, u_types_constants)
- plan:
1 - Introduction 1.1 Historique Les disquettes de l'Apple ][ pouvaient contenir 112.000 octets. Je les ai
utilisées pour gérer toutes mes commandes pendant des années. Un des problème les plus immédiat fut de pouvoir stocker efficacement des adresses. En effet, certaines personnes ont une adresse simple: Mr Jean DUPOND 5 Av de la Paix
75005 PARIS alors que pour d'autres clients c'était un peu plus long: Mr Jean Pierre COURTOIS DUGENOU Résidence Les Peupliers Val MireBois Bâtiment 8 Escalier 5 16367 LES CONDEES SUR SENLIS
Un fichier de taille fixe souffre des mêmes inconvénient qu'un ARRAY: - soit la taille est calculée trop juste, et certaines adresses ne pourront être stockées
- soit l'allocation est trop généreuse et une gâchis est fatal.
Une première solution est de stocker les adresses dans des fichiers ASCII munis d'un quelconque système de balises <début d'adresse> et <fin d'adresse>. C'est la solution que nous avions adoptées pour notre bibliographie (chaque livre
pouvant avoir plusieurs auteurs, des mots clés en nombre variable, et un descriptif aussi variable. Pour la gestion ceci n'était pas assez efficace: le fichier ASCII avec balise
doit être parcouru séquentiellement. Tant que je pouvais compter mes clients sur deux mains, pas de problèmes, mais au-delà d'une centaine le temps de recherche devient prohibitif.
D'où la seconde solution consistant à répartir l'information en deux fichiers: - un premier fichier contient la suite des caractère ASCII de chaque adresse.
- un second fichier ayant des fiches de taille fixe contient les positions des
adresses dans le premier fichier.
Nous bénéficions ainsi d'un stockage compace, tout en gardant l'accès direct. La technique de stockage de la position des adresse peut varier: - soit la position et la taille
- soit la position de début et la position de fin
- soit uniquement la position, le fichier variable contenant:
- soit la taille
- soit un marqueur de fin de chaîne (#0 par exemple)
Ces trois solutions sont optimales au niveau place. Les disquettes de l'Apple étant ce qu'elles étaient, il vallait mieux se prémunir contre un secteur foireux, et le stockage dans le fichier variable de la taille de chaque chaîne
(ou un marqueur final) permettait de relire le fichier variable sans l'aide du fichier d'accès. Pour faciliter une éventuelle reconstruction, j'avais aussi ajouté à chaque adresse, le numéro de fiche dans le fichier d'accès: au pire je
perdais 512 ou 1024 octets d'adresses, mais le reste des données était sauf. La version présentée ici n'est qu'une version dépoussiérée destinée
essentiellement à stocker les données des logs HTTP bruts. La particularité de ces logs est que plusieurs zones peuvent être
de taille variable (les URLs, les noms de pages, les noms de machines. J'ai donc ajouté la possibilité de placer dans chaque "champ" un identificateur de champ. 1.2 Le format retenu Le fichier d'accès contient dans chaque fiche:
- la position de la partie variable dans le fichier variable
- les coordonnées correspondant au fichier utilisateur: numéro de fiche et numéro de champ (dans le cas des logs, (ligne 14, champ URL) puis (ligne 14,
champ page_à_telecharger), par exemple
- la taille de la partie variable
Le fichier variable contient pour chaque champ variable: - les coordonnées correspondant au fichier utilisateur: numéro de fiche et
numéro de champ (dans le cas des logs, (ligne 14, champ URL) puis (ligne 14, champ page_à_telecharger), par exemple
- la taille de la partie variable
- les octets variables
2 - Utilisation
2.1 Le ficher variable L'interface est la suivante:
type t_variable_field_header= record
m_record, m_field, m_length: Integer;
end;
c_variable_file= class(c_basic_file)
public
m_first_free_position: Integer;
m_variable_field_header: t_variable_field_header;
Constructor create_variable_file(p_name, p_file_name: String); Virtual;
function f_force_create: Boolean; Override;
procedure append_string(var pv_variable_field_header: t_variable_field_header;
p_string: String; var pv_string_position: Integer);
procedure read_string(p_string_position: Integer;
var pv_variable_field_header: t_variable_field_header;
var pv_string: String);
Destructor Destroy; Override;
end; | Pour les données:
- t_variable_field_header définit l'en-tête figurant avant la partie variable. Elle comporte:
- m_record: le numéro de fiche dans l'application utilisatrice (la ligne du log HTTP, par exemple)
- m_field: le numéro du champ dans l'application utilisatrice (1 pour l'URL, 2 pour le service etc)
- m_length: la taille de la partie variable qui suit
Integer; - dans la classe c_variable_file
- m_first_free_position: la position du premier "trou" dans le fichier. La gestion d'une "free-list" n'est pas implémentée dans cette version, et ce champ est inutilisé (mais les 4 octets sont réservés au début du fichier disque).
- m_variable_field_header: la "fiche courante en mémoire" pour ce fichier
Et pour les méthodes: - create_variable_file: initialize les champs de la classe
- f_force_create: crée un nouveau fichier disque en détruisant le précédent au besoin
- append_string: ajoute une chaîne à la fin du fichier. La procédure remplit
le champ m_length et retourne aussi la position du premier octet stocké
- read_string: relit une chaîne dont on fournit la position de départ. Remplit aussi l'en-tête
2.2 Le ficher d'accès
L'interface est la suivante:
type t_direct_access_record= record
m_offset: Integer;
m_variable_field_header: t_variable_field_header;
end;
c_direct_access_variable_file= class(c_basic_file)
public
m_c_variable_file: c_variable_file;
m_direct_access_record: t_direct_access_record;
Constructor create_direct_access_variable_file(p_name, p_file_name: String); Virtual;
function f_force_create: Boolean; Override;
function f_open: Boolean; Override;
procedure close_file; Override;
function f_append_string(p_record, p_field: Integer; p_string: String): Integer;
function f_read_string: String;
Destructor Destroy; Override;
end;
| Pour les données: - t_direct_access_record: définit le type de l'enregistrement. Il comporte:
- m_offset: la position des données dans le fichier variable
- m_variable_field_header: une copie de l'en-tête dans le fichier variable (redondant)
- pour la classe c_direct_access_variable_file
- m_c_variable_file: la classe gérant les données variables
- m_direct_access_record: la fiche courante en mémoire
Et pour les méthodes: - create_direct_access_variable_file: construit la classe. Notons que
p_file_name est la "racine" du nom: les extensions ".dir" et ".var" seront ajoutées pour la partie accès direct et la partie variable
- f_force_create: crée deux fichiers vides, en détruisant toute version précédente
- f_open: ouvre les deux fichiers
- close_file: ferme les deux fichiers
- f_append_string: ajoute une chaîne:
- le programme utilisateur fournit
- p_record: le numéro de fiche (par exemple ligne 14 du log)
- p_field: le numéro du champ (par exemple 2 pour le Service)
- p_string: la chaîne (par exemple "SVC3")
- la fonction retourne le numéro de fiche dans le fichier d'accès
- f_read_string: retourne la chaîne correspondant à la fiche courante dans le fichier d'accès. Pour changer la chaîne lue, il faut d'abord effectuer un
positionnement par seek_file (position en octets)
2.3 - Répertoires et Directives de Compilation L'unité est prévue pour être placée dans: C: programs
colibri_helpers classes Vous pouvez naturellement changer cette organisation par Projet | Options | Directories Les directives de compilation sont:
- R+ (vérification des intervalles)
- S+ (vérification de la pile)
- pas d'optimisation
3 - Programmation Rien de particulier. Les deux classes s'appuient essentiellement sur la classe
u_c_basic_file. 4 - Améliorations La version actuelle n'est de loin pas optimale. J'ai expliqué plus haut que je
préférais assurer la reconstitution des fichiers en cas de problème disque. Peut-être suis-je allé un peu trop loin, et la sauvegarde avec chaque partie variable de la position dans le fichier variable ET l'identificateur de
l'enregistrement est un peu trop prudent. De façon similaire, l'utilisation du type Integer pour chaque valeur numérique est sans doûte exagérée: 4 Giga pour le nombre de champs, ou même pour la
taille de la partie variable est à l'évidence surdimensionné. Actuellement ces unités ont été essentiellent conçues pour le traitement des Logs: - manquent la gestion des modifications (remplacement en fin si la chaîne est
plus grande, gestion des trous)
- traitement des données autres que les String. La partie variable ne dépend pas du fait qu'il s'agit de caractères de String, mais les méthodes ne sont pas écrites.
Comme nous l'avons déjà signalé, les deux classes s'appuient essentiellement sur la classe u_c_basic_file. Or celle ci est marquée
essentiellement pour sa vocation de traitement de fichier chargé dans un tampon mémoire (le programme ED pour ne pas le nommer). La partie BlockRead et BlockWrite manque un peu de cohérence, et devrait vraissemblablement être
réécrite. En passant en plus par une classe intermédiaire de gestion de FILE OF (qui évite l'utilisation des SIZEOF pour gérer le fichier par fiche et non pas par octets). Nous avons maintenu l'héritage de c_basic_file:
- pour bénéficier de la gestion des erreurs
- pour pouvoir utiliser les possiblités de copie, archivage, changement de noms etc.
En l'absence de besoin de gestion d'erreur ou copie, une réécriture des deux
fichiers à partir de FILE ne serait pas un travail très important. Actuellement ce format est remplacé par le format plus simple décrit dans u_c_string_file.
5 - Télécharger le source Pour télécharger, cliquez: Avec les mentions d'usage:
- j'apprécie tous les commentaires, remarques ou critiques
- signalez-moi les bugs que vous trouverez.
L'auteur John COLIBRI est passionné par le développement
Delphi et les applications de Bases de Données. Il a écrit de nombreux livres et articles, et partage son temps entre le développement de projets (nouveaux projets, maintenance, audit, migration BDE, migration Xe_n, refactoring) pour ses clients, le
conseil (composants, architecture, test) et la
formation. Son site contient des articles
avec code source, ainsi que le programme et le calendrier des stages de formation Delphi, base de données, programmation objet, Services Web, Tcp/Ip et
UML qu'il anime personellement tous les mois, à Paris, en province ou sur site client. |