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

Langage Delphi Discussion :

Lecture rapide de fichier à partir de la ligne n : Possible?


Sujet :

Langage Delphi

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    177
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 177
    Points : 130
    Points
    130
    Par défaut Lecture rapide de fichier à partir de la ligne n : Possible?
    Bonjour, j’aurais besoin de vos conseils pour lire un fichier. J’utilise la version delphi6.

    Une application externe rempli un fichier log de n lignes toutes les x secondes.
    Une ligne ressemble à ["#code#","libelle code","",timespan]Message. Le nombre de lignes peut être illimité. Le fichier peut très bien atteindre un million de lignes au bout de 30 minutes d’activité.

    Mes questions sont :
    Comment on fait pour lire rapidement ce fichier pour le rendre de nouveau disponible à cette application?
    Est-ce possible de lire à partir de la ligne n (correspondant à un timespan donné).

    J’ai pensé à faire un LoadFromFile pour pouvoir libérer rapidement le fichier avec un compteur pour la dernière ligne traitée. Mais cette méthode m’oblige à lire entièrement le fichier. Sachant que plus le fichier sera gros, plus on perdra à chaque fois en efficacité (sans compter si le fichier contient déjà de ‘vieille’ données que le client veut conserver).


    Merci d'avance

  2. #2
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 173
    Points
    4 173
    Par défaut
    Citation Envoyé par Arsenic68 Voir le message
    Est-ce possible de lire à partir de la ligne n (correspondant à un timespan donné).
    Non, ce n'est pas possible. Pas sous cette forme.

    J'ai l'impression qu'en fait, ce que tu cherches à faire, c'est qu'une deuxième application viennent périodiquement lire le log pour traiter les nouvelles lignes qui sont apparues depuis le dernier traitement.
    Dans ce cas, tu peux presque faire ce que tu veux, si tu ouvres ton fichier en binaire et non pas en texte.
    Sur un fichier binaire, tu peux l'ouvrir et le lire à partir d'une certaine position. Donc il te suffit de mémoriser la position à laquelle tu t'étais arrêtée pour reprendre le traitement à cet endroit la fois suivante (un simple Seek permet de se repositionner à l'intérieur du fichier).
    Par contre, ça veux dire que tu dois ouvrir le fichier en binaire, et faire le découpage en lignes toi même.

    De plus, pour éviter de trop perturber l'appli qui génère le log, tu peux essayer d'ouvrir le fichier en mode GENERIC_READ + FILE_SHARE_READ + FILE_SHARE_WRITE (fmOpenRead + fmShareDenyNone dans TFileStream) de façon à ce que ta lecture du fichier n'interdise pas à l'appli qui génère le log d'ouvrir et modifier le fichier en même temps. Mais ça ne pourra marcher que si de son côté l'appli qui génère le log n'ouvre pas le fichier en mode exclusif (ce qui est loin d'être gagné !).

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    177
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 177
    Points : 130
    Points
    130
    Par défaut
    Tu as bien compris le rôle de mon appli.

    Pour l'appli qui génère, j'ai aucune idée du mode dans lequel il ouvre son fichier.

    Je vais donc devoir parcourir octet par octet à la recherche du caractère #13?


    Par contre, je vois pas l'interêt du mode FILE_SHARE_WRITE, je ne vais rien écrire dedans.
    Je me perds dans tous les types de fichier qui existe. C'est quoi le meilleur et les differences entre ces types?

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 665
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 665
    Points : 25 459
    Points
    25 459
    Par défaut
    Tient regarde ma classe TTextFileReader (fait une recherche sur le forum, bcp de sujet similaire sur les gros fichiers auxquels j'ai répondu y font référence), on pourrait imaginer, un système où l'on réclame la mise à jour de l'index à fur et à mesure que le fichier grandi (à condition que le Share soit possible) au lieu de le regénérer à chaque fois, selon le principe de conservation de la dernière position (le dernier item de l'index finalement) ...

  5. #5
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    Bonjour,

    "Padder" (compléter par des blancs à droite) les lignes de texte à une longueur fixe maxi permettrait de traiter le fichier Ascii de log comme un fichier record.
    La longueur d'un enregistrement sera égale à la longueur fixe + 2 octets pour le CRLF.

  6. #6
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    177
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 177
    Points : 130
    Points
    130
    Par défaut
    @ShaiLeTroll j'ai pas très bien compris comment ta classe fonctionne.

    Tu crer ton TTextFileReader, tu demande la création de l'index puis tu readLine jusqu'à la prochaine mise a jour de l'index ? J'avoue ne pas très bien saisir la différence entre readLine et readString.


    @Grafitto : J'ai absolument pas compris comment ça marche un fichier record (mais le principe a l'air bien)

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 665
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 665
    Points : 25 459
    Points
    25 459
    Par défaut
    ReadLine est libre, tu lit le fichier via l'index
    ReadString est fixe, tu lit le fichier séquentiellement, tu avances toujours ...

  8. #8
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    Dans ce tuto : les fichiers "record" sont appelés fichiers séquentiels.
    http://fbeaulieu.developpez.com/guid...age_13#LXIII-C
    pour se positionner dans le fichier : instruction seek.

  9. #9
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    177
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 177
    Points : 130
    Points
    130
    Par défaut
    Je sais pas trop si le fichier record pourrait être utiliser. En effet, le libelle du code a une taille variable entre 6 et 21, donc je pourrais extraire que le code. De plus padder va prendre du temps machine, on risque de perdre plus qu'on en gagne.

    Avec un onChanged de System.IO.FileSystemWatcher pour la mise a jour de l'index et ton readString ça devrait être bon non?

  10. #10
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 665
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 665
    Points : 25 459
    Points
    25 459
    Par défaut
    Effectivement, prend l'idée fourni par Franck SORIANO et étudie le code de lecture de ReadString pour une lecture binaire, et tu aurais effectivement le résultat souhaité ...

  11. #11
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    177
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 177
    Points : 130
    Points
    130
    Par défaut
    J'ai testé ta classe mais j'ai un problème de lenteur et de fin de fichier.
    J'ai l'impression que l'indexage c'est mal passé. Le fichier idx a bien été créer mais count renvoie 0
    Pour parcourir mon fichier de 13 200 lignes, il faut presque 3 minutes pour que ce code s'exécute.
    Le fichier lu est indisponible pour l'application externe.
    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
    procedure TfmAccueil.bt_goClick(Sender: TObject);
    begin
      bt_stop.Enabled := true ;
      bt_go.Enabled := false ;
      currentFile := ini.ReadString(currentUser,'loc','');
      bPause := false ;
     
      Mettre_Au_Rouge(StatusBar1);
      StatusBar1.Panels[1].Text := 'Lecture du fichier';
      parse:=TParser.create(currentFile);
      try
        parse.lire;
      except
        on E : Exception do
            showmessage(E.Message);
      end;
      Mettre_Au_Vert(StatusBar1);
      //Timer1.Enabled := true ;
    end;
    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
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    unit classParser;
     
    interface
    uses classes,SysUtils,Dialogs,
        UnitException,unitTextFileReader,UnitChaine;
     
    type TLigne = record
        code : string[18] ;
        timespan : Cardinal ;
        message : shortstring ;
    end;
     
     
    type TParser = class
      private
        _file : TTextFileReader ;
        _currentline : Cardinal ;
        _path : string ;
     
        procedure traiterligne(pligne : string);
      public
        constructor Create(path : string);
         destructor Destroy;override;
         procedure MAJ ;
         procedure lire ;
      protected
    end;
     
    var bPause : boolean ;
     
    implementation
     
    { lecteur }
     
    constructor TParser.Create(path : string);
    begin
      _currentline := 0 ;
      if FileExists(path) then begin
        _path := path;
        _file := TTextFileReader.Create(path);
        _file.BuildLinesIndexes ;
      end
      else
        raise EFichierIntrouvable.createRes(@sFichierIntrouvable) ;
    end;
     
    destructor TParser.Destroy;
    begin
        _file.Free ;
    end;
     
    procedure TParser.lire;
    var ligne : String ;
    begin
      while (ligne<>'') do
      begin
        ligne := _file.ReadLine(_currentline);
        traiterligne(ligne);
        inc(_currentline);
      end;
      showmessage(inttostr(_currentline));
    end;
    procedure TParser.traiterligne(pligne : string);
    var indexDebutMessage : Byte ;
        code : string[18] ;
        ligne : TLigne ;
    begin
        ligne.code :=  copy(pligne,3,18);
        ligne.timespan :=0;//strtointdef(copy(Mot(pligne,'",',3),0,10) ,0);
        indexDebutMessage := Pos(']',pligne)+1;
        ligne.message := copy(pligne,indexDebutMessage,length(pligne)-indexDebutMessage+1);
    end;
    end.

  12. #12
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 665
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 665
    Points : 25 459
    Points
    25 459
    Par défaut
    Euh, trois minutes, ça doit être le temps pour un fichier de 500 Mo avec plus de 4 millions de lignes ...
    Le BuildLinesIndexes ne fait que construire le fichier d'index, il faut spécifier explicitement son utilisation avec la propriété Indexed ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        _file := TTextFileReader.Create(path);
        _file.BuildLinesIndexes ;
        _file.Indexed := True;
    Par contre, on ne met pas _ mais F, Object Pascal Style Guide

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    type TParser = class
      private
        FFile : TTextFileReader ;
        FCurrentLine : Cardinal ;
        FPath : string ;
    Tient, tu peux aussi avoir un problème, si tu as une ligne vide (deux fois de suite CRLF CRLF, je n'ai pas testé, mais ça doit donner une ligne vide car longueur zéro)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    procedure TParser.lire;
    var
     ligne : String ;
    begin
      FCurrentLine := 0;
      while FCurrentLine < Reader.Count do
      begin
        ligne := _file.ReadLine(FCurrentLine);
        traiterligne(ligne);
        inc(FCurrentLine);
      end;
      showmessage(inttostr(FCurrentLine));
    end;

  13. #13
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    177
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 177
    Points : 130
    Points
    130
    Par défaut
    Alors le fichier il fait 1683 Ko et toutes les lignes sont pleines sauf la dernière.

    Si je fais indexed puis build il me sort une violation d'accès. L'inverse par contre a l'air de marcher.
    Ton Reader est de quel type ? TTextFileReader? Si c'est ça le count n'a pas bouger d'un poil. Mais quand on inspecte l'objet, il vaut bien le nombre de ligne

    le _ vient du fait que c'est privé dixit mon chef

  14. #14
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 665
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 665
    Points : 25 459
    Points
    25 459
    Par défaut
    le _ c'est en C, pas en Delphi, ton chef t'apprend mal les choses, le _ est toléré pour les déclarations windows ou alors pour les bidoubilles de variables globales privées pour simuler une propriété de classe qui n'existe pas en Delphi (les vieux) contrairement au Java

    Sinon, pour la Violation d'Accès, ouais, j'ai pas sécurisé, et d'ailleurs, j'avais bien mis dans mon exemple Indexed après BuildLinesIndexes, tu peux mettre aussi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        _file := TTextFileReader.Create(path);
        _file.AutoIndexed := True;
        _file.Indexed := True;
    Pour la valeur au débogage, ouais c'est pas toujours le top, d'ailleurs, le Count (FIndexCount) est rempli lorsque de Set de Indexed à True, ... et il est facile à calculer, c'est la taille du fichier d'index divisé par 12 (taille d'un TTextFileReaderIndex)

    euh oui, Reader c'était ton _File, ...

  15. #15
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    177
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 177
    Points : 130
    Points
    130
    Par défaut
    J'ai mis les 2 a true et toujours pas accès a eof et count. J'y accède comment a part ouvrir un filestream a part?

  16. #16
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 665
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 665
    Points : 25 459
    Points
    25 459
    Par défaut
    Hein ???
    Ben que veux tu, ton fichier n'est peut-être pas compatible ... je peux pas deviner sans matière ...

  17. #17
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    177
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 177
    Points : 130
    Points
    130
    Par défaut
    ["#0000000042000004#","Other hit by nano","",1217771440]Ensign - Cha'Heru was attacked with nanobots from Nisie for 4852 points of radiation damage.
    ["#0000000042000004#","Other hit by nano","",1217771440]Ensign - Cha'Heru was attacked with nanobots from Nisie for 7133 points of radiation damage.
    ["#0000000042000004#","Other hit by nano","",1217771440]Ensign - Cha'Heru was attacked with nanobots from Nisie for 7417 points of radiation damage.
    ["#000000004200000a#","Other hit by other","",1217771440]Snakeye15 hit Fleet Commander - Rimah'Nakthi for 1651 points of fire damage.
    ["#000000004200000a#","Other hit by other","",1217771440]Haela hit Ensign - Cha'Heru for 1210 points of energy damage.
    Voila la fin de mon fichier. C'est normal qu'on est a plus de 6 millions de lecture E/S avec un fichiers de 13200 lignes?

  18. #18
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 665
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 665
    Points : 25 459
    Points
    25 459
    Par défaut
    Comment compte les opérations E\S ? Avec Process Monitor ?
    Maintenant, as-tu vu un fichier .idx créé dans le même répertoire que ton fichier ?

  19. #19
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    177
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 177
    Points : 130
    Points
    130
    Par défaut
    Oui, je le vois avec le gestionnaire des tâches.

    Le fichier existe bien dans le dossier, c'est justeement pour ça que je trouve bizarre que j'ai pas accès a count et eof

  20. #20
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 665
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 665
    Points : 25 459
    Points
    25 459
    Par défaut
    Ah, oki pour le Gestionnaire ...
    Sinon, le fichier fait qu'elle taille ? et que contient-il ?

Discussions similaires

  1. [dlmread] lecture de fichier à partir de la ligne 2
    Par polopolo81 dans le forum MATLAB
    Réponses: 3
    Dernier message: 06/04/2011, 14h17
  2. Réponses: 0
    Dernier message: 16/06/2010, 12h36
  3. Réponses: 3
    Dernier message: 03/01/2008, 12h14
  4. Lecture d'un fichier à partir de la nième ligne
    Par May69 dans le forum Entrée/Sortie
    Réponses: 2
    Dernier message: 17/02/2007, 09h29
  5. Lecture d'un fichier à partir d'un formulaire
    Par Dirty Harry dans le forum Langage
    Réponses: 7
    Dernier message: 01/02/2007, 16h39

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