IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Gérer des fichiers "à pas fixe" ou "record" avec C#


Sujet :

C#

  1. #1
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut Gérer des fichiers "à pas fixe" ou "record" avec C#
    Bonjour,

    Je viens de retomber sur un vieux code que j'ai écrit, qui permet de générer un fichier à pas fixe (ou record) à partir d'une description du fichier.

    J'avais essayé de le rendre le plus générique possible (en passant notamment par un fichier de description des champs en XML) mais la solution que j'avais adopté me semble très lourde par rapport à ce que savait faire VB en natif par exemple.

    Exemple de fichier " pas fixe" :

    Nom : String / Position 1 / Longueur 20
    Prenom : String / Position 21 / Longueur 20
    Age : Int / Position 41 / Longueur 3

    J'ai matérialisé les sauts à la ligne par des \n
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    Alfred              Dupont              25 \n
    Jules               Desbois             43 \n
    Henriette           Dupuis              103\n
    Ce genre de fichiers sont très utilisés dans les EDI et autres transferts inter-systèmes. Le XML n'a pas tout remplacé, loin de là. Et niveau performances, y'a rien de mieux que ce genre de fichiers, le XML étant une usine à gaz à côté.

    En VB, ça se lisait/écrivait très facilement (à la faute de syntaxe près, ça fait longtemps que j'ai pas fait de VB ^^)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    Type Personne
       Prenom As String*20
       Nom As String*20
       Age As String*3
       CrLf as String*2
    End Type
     
    Sub ReadFile()
      Open FileName For Random Access Read As #FileNbr Len = Len(Personne)
      Dim P as Personne
      Do Until EOF(FileNbr)
         Get #FileNbr, , P
         MsgBox("La personne " & P.Prenom & " " & P.Nom & " a " & P.Age & " ans.")
       Loop
       Close #FileNbr
    End Sub
    En C#, c'est une véritable usine à gaz pour reproduire la même chose, à ma connaissance tout du moins.

    Avant que je poste ce que j'avais fait, déjà, est-ce que vous avez des solutions "génériques" pour faire ça ?
    C'est à dire du code qui évite de noyer 25 sous-chaines avec des nombres magiques sur 50 lignes.

    Le but étant d'avoir en sortie :
    - Un objet représentant une ligne "typée" du fichier (il peu y avoir des personnes, mais aussi d'autres types de records)
    - Dont les champs sont accessibles facilement, comme dans une structure
    On ne jouit bien que de ce qu’on partage.

  2. #2
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Aucun succès, c'est fou !

    Personne n'est amené à travailler avec ce genre de fichiers ?

    Suis-je le seul ?

    Bon, en tout cas, je me suis amusé à réécrire une bibliothèque générique permettant de gérer ce genre de fichiers.

    Actuellement, il s'agit d'une version très basique, qui ne gère qu'un type de record par fichier.

    Je la ferai peut-être évoluer selon vos remarques ou besoins... si quelqu'un daigne poster dans ce topic !

    Voici comment utiliser la lib :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
     
    using System;
    using System.Text;
    using FlatFileManager;
     
    namespace Test
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Définition du format des variables");
     
                FlatFileInfo ffi = new FlatFileInfo("yyyyMMdd", ".", Encoding.ASCII);
     
                Console.WriteLine("Lecture de la définition du format de fichier \"personne\"");
     
                RecordInfo rcp = new RecordInfo("personne");
                FlatFile file = new FlatFile(ffi, rcp);
     
                Console.WriteLine("Lecture du fichier \"personnes.txt\"");
                file.Load("personnes.txt");
     
                foreach (Record r in file)
                {
                    Console.WriteLine("{0} {1} a {2} ans.", r["prenom"], r["nom"], r["age"]);
                }
     
                rcp = new RecordInfo("produit");
                file = new FlatFile(ffi, rcp);
                file.Load("produits.txt");
     
                Console.WriteLine("Lecture du fichier 'produits.txt'");
                foreach (Record r in file)
                {
                    Console.WriteLine("Code : {0} Nom : {1} DLC : {2} Prix : {3} EUR", r["code"], r["nom"], r["dlc"].DateValue.ToShortDateString(), r["prix"]);
                }
     
                rcp = new RecordInfo("test");
                file = new FlatFile(ffi, rcp);
                Record rec = new Record(rcp);
                rec["teststring"].SetValue("test string");
                rec["testdatetime"].SetValue(DateTime.Today);
                rec["testint"].SetValue(12);
                rec["testdecimal"].SetValue(3.45);
                file.Records.Add(rec);
     
                rec = new Record(rcp);
                rec["teststring"].SetValue("test 2");
                rec["testdatetime"].SetValue(DateTime.Today.AddDays(10));
                rec["testint"].SetValue(123);
                rec["testdecimal"].SetValue(4.5);
                file.Records.Add(rec);
     
                file.Save("test.txt");
     
                Console.ReadKey(true);
            }
        }
    }
    Cet exemple charge deux fichiers et affiche leur contenu, avant d'en créer un troisième.

    J'espère que vous la trouverez utile et simple d'utilisation (c'était l'unique but recherché).
    Fichiers attachés Fichiers attachés
    On ne jouit bien que de ce qu’on partage.

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Il y a une classe TextFieldParser qui sait faire ce genre de choses (pour des champs à largeur fixe ou avec séparateurs). Elle est dans l'assembly Microsoft.VisualBasic (va savoir pourquoi), mais rien n'empêche de référencer cet assembly depuis C# et d'utiliser la classe

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Sinon, concernant ta solution, y a juste un truc qui me gêne : l'utilisation d'un singleton pour FlatFileInfo. Ca aurait un sens si tous les fichiers plats avaient le même séparateur et le même format de date, mais dans la vraie vie ce n'est pas le cas... Donc cette info ne devrait pas être globale, elle devrait plutôt être spécifique à chaque fichier plat.

  5. #5
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    C'est effectivement ce que je me suis dis lors de son utilisation, mais c'était pour voir comment marchait un "vrai" singleton

    Je vais y apporter quelques modifications : idem, l'encodage est actuellement en dur, et devrait être dans FlatFileInfo...

    Par contre, je suis un peu deg pour le coup de la class déjà existante... Je vais voir à quoi ça ressemble
    On ne jouit bien que de ce qu’on partage.

  6. #6
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Ca me revient pourquoi j'étais passé par un Singleton

    Comment on fait une variable globale en C# ?

    Bon, j'ai esquivé en mettant les infos en Thread.CurrentThread.CurrentCulture lors du Load et du Save, mais j'aimerais bien savoir comment gérer des variables globales... locales à l'appelant !

    Comme c'est le cas en VB par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    Sub Test0
       Call Test1()
    End Sub
     
    Sub Test1
       Dim a as integer
       Call Test2()
    End Sub
     
    Sub Test2
       Dim b as integer
       Call Test3()
    End Sub
     
    Sub Test3
       Dim c as integer
    End Sub
    => Dans Test0, on n'a accès à aucune variable
    => Dans Test1, on a accès à "a"
    => Dans Test2, on a accès à "a" et "b"
    => Dans Test3, on a accès à "a", "b" et "c"

    En .NET ça n'existe pas : on n'a accès qu'aux variables locales à la méthode courante... et aux singletons (ou classes avec contructeur static).

    Le seul souci, c'est que les singletons/classes avec contructeur static, c'est de portée globale à l'application. Moi j'aimerais que si j'ai une instance de FlatFile, une de ses variables soit visible dans tous ses enfants, mais qu'une autre instance de FlatFile puis cohabiter avec d'autres variables.

    Y'a moyen de faire ça ?
    On ne jouit bien que de ce qu’on partage.

  7. #7
    Membre confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2009
    Messages
    317
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Finance

    Informations forums :
    Inscription : Février 2009
    Messages : 317
    Points : 560
    Points
    560
    Par défaut
    Ca ne serait pas une variable déclaré protected dont tu parles ?

  8. #8
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Non, ça c'est de l'héritage.

    Moi je parle de ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    class A
    {
         B b;
         int Youpi = 1;
     
         public A()
         {
            b = new B();
         }
    }
     
    class B
    {
         public B()
         {
             // Je veux pouvoir utiliser a.Youpi sans pour autant devoir le recevoir en paramètre
         }
    }
    Sans notion d'héritage : A et B n'ont pas du tout la même structure.

    Je parle bien de "a.Youpi", c'est à dire l'instance de A qui est le parent de l'objet b. Je ne parle pas d'une variable static, qui sera la même dans toutes les instances de tous mes objets.
    On ne jouit bien que de ce qu’on partage.

  9. #9
    Membre confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2009
    Messages
    317
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Finance

    Informations forums :
    Inscription : Février 2009
    Messages : 317
    Points : 560
    Points
    560
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    class A
    {
                B b;
                public int Youpi = 1;
     
                public A()
                {
                    b = new B();
                    b.a = this;
                }
    }
     
    class B
     {
                public A a;
                public B()
                {
                    a.Youpi = 2;
                    // Je veux pouvoir utiliser a.Youpi sans pour autant devoir le recevoir en paramètre
                }
     }
    Comme ça ?

    Bon c'est du chipotage, mais au moins tu le passes pas en paramètre :p xD

    Bon ça va j’arrête ...

  10. #10
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Oui mais justement, c'est bien ça que je veux éviter

    Je vais éviter de pourrir mon propre topic, donc je vais créer un autre topic
    On ne jouit bien que de ce qu’on partage.

  11. #11
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Citation Envoyé par StringBuilder Voir le message
    Comment on fait une variable globale en C# ?
    Avec des propriétés statiques, ou un singleton... mais pourquoi voudrais-tu que ce soit global ?

    Ma remarque portait justement sur le point que ces paramètres ne devraient pas être globaux. Suppose que 2 threads manipulent des fichiers plats qui ont des caractéristiques différentes : si les paramètres sont globaux, tes deux threads vont se marcher dessus...

    Dans ton code modifié, c'est propre : chaque FlatFile à son propre FlatFileInfo, donc pas de problème

Discussions similaires

  1. [SSH2] Utiliser scp pour gérer des fichiers distants
    Par cybercandyman dans le forum Bibliothèques et frameworks
    Réponses: 4
    Dernier message: 12/11/2007, 17h03
  2. Cherche librairie pour gérer un fichier XML (pas un parser)
    Par batataw dans le forum Format d'échange (XML, JSON...)
    Réponses: 2
    Dernier message: 20/10/2007, 23h18
  3. Choix SGBD pour gérer des fichiers Excel et des images ?
    Par benoit69 dans le forum Décisions SGBD
    Réponses: 3
    Dernier message: 01/03/2007, 12h02
  4. Gèrer des fichiers (documents .doc) via Struts.
    Par LESOLEIL dans le forum Struts 1
    Réponses: 7
    Dernier message: 22/08/2005, 16h26
  5. Réponses: 5
    Dernier message: 28/04/2004, 15h20

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo