Home (autres pages) Léa Linux TrustOn Me OpenVPN French Linux Doc Project

Introduction

La dernière fois que j'ai jeté un oeil sur les changements de la distribution Fedora, j'ai remarqué qu'ils avaient ajouté unenvironnement de développement pour le langage D.

Par curiosité, je me suis demandé ce que pouvait bien être ce nouveau langage...

Ce que j'ai noté de vraiment intéressant :

  • il s'inspire de langages comme le C++ et le Java
  • il dispose d'un « ramasse-miettes » (ou garbage collector)
  • il est orienté objet avec une notion d'héritage simple)

Il y a quelques temps, j'avais eu une discussion à propos d'algorithmie. En fin de discussion, il s'est avéré qu'il y a deux sortes d'algorithmiciens :

  • ceux qui pensent que la gestion de la mémoire fait partie intégrante de l'algorithme, avec toutes les conséquences en terme de compléxité,
  • ceux qui pensent que le contraire et sont ravis de se centrer sur l'algorithme plutôt que la gestion de la mémoire.

Personnellmement, je suis partisan du "ramasse-miettes" car cela permet tout de même d'obtenir une vue plus "élégante"sur un problème.

Pour télécharger, cela se passe sur le site de DigitalMars.

Proposition d'un petit programme

Le programme que je propose est un outil de type "sécurité" : il permet de dresser une liste exhaustive de fichiers avec un hash de type MD5 ou fournit les différence avec une liste préalablement établie.

En gros, nous avons :

  • construction d'une base avec les informations relatives à chaque fichier (MD5,
  • attributs, dates, ...)
  • relecture d'une base
  • comparaison de deux bases

Accessoirement :

  • lecture d'un fichier de configuration
  • affiche d'une base

Les imports

Comme pour un programme de type Java, il suffit d'importer les bibliothèques mettant à disposition les fonctions que nous allons utiliser :

  • std.string pour la gestion des chaînes de caractères,
  • std.md5 pour la création des hashes MD5,
  • std.stream pour la gestion des fichiers en mode flux,
  • std.bitmanip pour créer et manipuler une structure en "bits",
  • std.date pour gérer les dates,
  • std.algorithm pour récupérer la fonction de trie.

Le reste est assez convenu, je ne citerai que core.thread que j'ai essayé d'utiliser mais sans réel succès.


Les fonctions

Ecriture d'un fichier

Je passe par un flux mémoire pour me permettre de réaliser des tâches supplémentaires avant d'écrire sur disque, pour des raisons de sécurité. Toutefois, comme je n'ai pas encore trouvé comment crypter les données, elles sont écrites directement sur disque...

        Stream sout = new MemoryStream();
        Stream fout = new BufferedFile(db_filename, FileMode.OutNew);
        
        writefln("SaveBase");

        foreach (cMD5Assoc element; list) {
                with (element) {
                        sout.writeBlock(&fSize, fSize.sizeof);
                        sout.writeBlock(&fFtc, fFtc.sizeof);
                        sout.writeBlock(&fFtc, fFtc.sizeof);
                }
        }
        
        // ici on crypte, on compresse, on fait ce que l'on a à faire...
        sout.position(0);
        fout.copyFrom(sout);
        sout.close();
        fout.close();

Lecture d'un fichier

Assez bizarrement, je n'ai pas trouvé beaucoup d'exemples sur la lecture et l'écriture de fichiers, surtout en mode binaire...

Voici un exemple tiré du programme, j'utilise les objects de type "flux de données". Un problème toutefois... il y une erreur si les noms de fichiers possèdent des accents:

        cMD5Assoc[] list;
        cMD5Assoc assoc;
        uint i = 0;
                
        writefln ("lecture de la base %s", db_filename);
        Stream sin = new BufferedFile(db_filename, FileMode.In);
        
        while (sin.position < sin.size) {
                assoc = new cMD5Assoc();
                with (assoc) {
                        sin.readBlock(&fFtc, fFtc.sizeof);
                        sin.readBlock(&fFtc, fFtc.sizeof);
                        sin.readBlock(&fFtm, fFtc.sizeof);
                }
                list ~= assoc;
        }
        
        sin.close();

A noter que la concaténation pour les tableaux utilise l'opérateur "~", très pratique.

Définition d'une structure de type "bits"

struct sCompare
{
    union
    {
        double value;
        mixin(bitfields!(
                        bool, "ok", 1,
                        bool, "nok", 1,
                        bool, "digest", 1,
                        bool, "filesize", 1,
                        bool, "ftc", 1,
                        bool, "ftm", 1,
                        bool, "fta", 1,
                        bool, "lm", 1,
                        bool, "attributs", 1,
                        ubyte, "buf", 7));
        }
}

Changement de type (ou typecast)

A un moment, je me suis posé une question... mais comment changer le type d'une variable ! surtout comment arrondir une valeur !

Ci-dessous, un code qui fonctionne mais est-ce la bonne méthode ?

uint round = to!uint(fileList.length / nb_threads);

La fonction de hashage MD5

J'ai un peu cherché pour faire fonctionner cette fonction... Premier problème, cela a été l'ouverture du fichier... Ensuite l'utilisation de la fonction std.md5.. Bref, voilà ce que j'ai pu faire (dans le programme, ce code est imbriqué dans un bloc "try ... catch") :

 bool MDFile(string filename, ubyte* input, bool quiet)
{
        auto f = new std.stdio.File(filename, "r");
        ubyte[16] digest;
                
        MD5_CTX context;
        context.start();
        
        foreach (ubyte[] buffer; f.byChunk(4096)) {
                context.update(buffer);
        }

        context.finish(digest);

        f.close();

        input[0 .. digest.length] = digest;
        return true;
}

Multitâches

L'objectif était de rendre le calcul de la liste des fichiers plus rapide en découpant par morceaux de liste... Mais a priori, il y a un problème de concurrence sur quelque chose et le programme se bloque ! Je n'ai toujours pas trouvé pourquoi... Donc pour le moment, je n'en parlerai pas ;)


Compilation et tests

Le programme complet est téléchargeable ici et est proposé à titre d'exemple sans garantie d'aucune sorte. N'hésitez pas à proposer vos modifications.

La compilation se fait comme suit :

# dmd check.d

Et ensuite un petit fichier de configuration comme par exemple :

dir=c:\test
dir=c:\docs
dbfile=d:\check\dbmd5.lst
quiet=1

Puis

# check build
....
# check compare

Conclusion

Ce langage est plutôt intéressant mais manque de maturité. A priori, il y a une librairie de fonctions plutôt sympas mais pas mis à jour depuis février 2010 et qui n'est pas forcément compatible avec les spécification de la version 2.0 du langage D !

Il n'y a pas beaucoup de documentations sur le sujet, surtout en français... Je ne suis pas arrivé à faire fonctionner le multithreads... ou encore la recopie de mémoire... et certains fichiers sous Windows (en mode console) ne sont tout simplement pas ouvert à cause des caractères accentués !

Bref malgré beaucoup de choses intéressantes, tout un tas de petites problèmes plutôt agaçants.... Je vais suivre l'avancée de ce langage et son itnégration dans les environnements graphiques tels que KDE ou Gnome car cela pourrait vraiment lui permettre de se faire connaître et reconnaître...

Affaire à suivre donc !

Me contacter | ©2004-2005 Raum