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

 Delphi Discussion :

[D2009] TFileStream Big Files (demande de conseil)


Sujet :

Delphi

  1. #41
    Membre éprouvé
    Avatar de Dr.Who
    Inscrit en
    Septembre 2009
    Messages
    980
    Détails du profil
    Informations personnelles :
    Âge : 45

    Informations forums :
    Inscription : Septembre 2009
    Messages : 980
    Points : 1 294
    Points
    1 294
    Par défaut
    tout a fait :

    string[7] = 7 caractere pas 8, un string commence à 1 pas comme les tableau dynamique

    setlength(dynarry, 8) = 0..7
    setlength(string, 8) = 1..8

    par contre oui il y a un petit soucis avec ShortString ou String :

    le byte reservé de la chaine pour la taille de cette derniere peut dans certains cas etre enregistré dans la structure.
    1 avantage et 1 inconvénient :

    avantage :
    quand on cherche "bonjour", inutile de chercher dans les lignes de taille inferieur ou superieur à 7.
    plutot que de lire la chaine complete on peut juste lire le byte de taille.

    inconvénient :
    il faut inclure le byte de taille dans la taille de la structure. sinon erreur.


    donc :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
      TFileStruc = record
        NumFact : String[8]; // 8 Caractères
        NumCompte : String[9]; // 9 Caractères
        Date : String[6]; // 6 Caractères
        FinLigne : byte; // 1 Caractère // << pas de string pour ça.
      end;

  2. #42
    Membre éprouvé Avatar de BuzzLeclaire
    Homme Profil pro
    Dev/For/Vte/Ass
    Inscrit en
    Août 2008
    Messages
    1 606
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Dev/For/Vte/Ass

    Informations forums :
    Inscription : Août 2008
    Messages : 1 606
    Points : 1 113
    Points
    1 113
    Par défaut
    Citation Envoyé par Dr.Who Voir le message
    tout a fait :
    donc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
      TFileStruc = record
        NumFact : String[8]; // 8 Caractères
        NumCompte : String[9]; // 9 Caractères
        Date : String[6]; // 6 Caractères
        FinLigne : byte; // 1 Caractère // << pas de string pour ça.
      end;
    Euh... là y a mal donne...

    8+9+6+1 = 27 octets
    taille fichier = 48 octects (rappel 24 caractères par ligne)
    Count = 1 (forcément 48 div 27) donc là il li même pas la deuxieme ligne

    De tout façon il ne trouve jamais le 'F' de la première ligne donc doit y avoir un gros bg probleme sur le FView.pas ? non ?


    Montor : tu veux parler de cela ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    type
      TFileStrucList = packed record
        datas : array[0..3] of PFileStruc;
        count : integer;
      end;

  3. #43
    Membre éprouvé Avatar de BuzzLeclaire
    Homme Profil pro
    Dev/For/Vte/Ass
    Inscrit en
    Août 2008
    Messages
    1 606
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Dev/For/Vte/Ass

    Informations forums :
    Inscription : Août 2008
    Messages : 1 606
    Points : 1 113
    Points
    1 113
    Par défaut
    Pour essai.. parcque là je deviens fou...lol

    Unit complet (ajouter le FView de dr. Who plus bas)

    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
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    unit Unit1;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, FView;
     
    type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
      type
      PFileStruc = ^TFileStruc;
      TFileStruc = record
        NumFact      : String[8]; // 8 Caractères
        NumCompte    : String[9]; // 9 Caractères
        Date         : String[6]; // 6 Caractères
        FinLigne     : Byte; // 1 Caractère
      end;
     
    const
      SizeOfFileStruc = SizeOf(TFileStruc);
     
    type
      TFileStrucList = packed record
        datas : array[0..3] of PFileStruc;
        count : integer;
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    procedure TForm1.Button1Click(Sender: TObject);
    var
      FV : TFileView;
      PFS : PFileStruc;
      Count, N : integer;
      list : Tlist;
      FS: TFileStruc;
      I: Integer;
    begin
      FV := TFileView.Create('C:\essai\essai.txt');
      list := Tlist.Create;
      try
        if FV.Loaded then
        begin
          PFS := FV.View; // on lit PFileStruc par PFileStruc
          showmessage(
          'Taille Structure = '+inttostr(SizeOfFileStruc)+ #13+#10+
          'FileSize = '+Inttostr(FV.FileSize)+ #13+#10 +
          'Count = ' + inttostr(FV.FileSize div SizeOfFileStruc)
          );
          Count := FV.FileSize div SizeOfFileStruc; // nombre d'elements
          for N := 0 to count-1 do
          begin
              List.Add(Pointer(integer(FV.View) + (SizeOfFileStruc*N)));
          end;
        end;
        for n := 0 to List.Count - 1 do
        Begin
          FS := PFileStruc(List.Items[n])^;
          Showmessage
          ('NumFacture : ' + FS.NumFact +#13+#10+
          'NumCompte : '+ FS.NumCompte +#13+#10+
          'Date : '+FS.Date +#13+#10
    //      'Libelle : '+FS.Libelle +#13+#10+
    //      'Debit '+FS.Debit +#13+#10+
    //      'Credit '+FS.Credit
    );
        End;
      finally
        FV.Free;
      end;
    end;
    end.
    Fichier txt ci-joint
    Fichiers attachés Fichiers attachés

  4. #44
    Membre éprouvé
    Avatar de Montor
    Homme Profil pro
    Autre
    Inscrit en
    Avril 2008
    Messages
    879
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Avril 2008
    Messages : 879
    Points : 963
    Points
    963
    Par défaut
    il y aun octet qui indique la taille de chaine

  5. #45
    Membre éprouvé
    Avatar de Montor
    Homme Profil pro
    Autre
    Inscrit en
    Avril 2008
    Messages
    879
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Avril 2008
    Messages : 879
    Points : 963
    Points
    963
    Par défaut
    type
    TFileStrucList = packed record
    datas : array[0..3] of PFileStruc;
    count : integer;
    end;
    non cette strucrure est déja packer

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    TFileStruc = packed record
     data:array[0..23] of byte
    end;

  6. #46
    Membre éprouvé Avatar de BuzzLeclaire
    Homme Profil pro
    Dev/For/Vte/Ass
    Inscrit en
    Août 2008
    Messages
    1 606
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Dev/For/Vte/Ass

    Informations forums :
    Inscription : Août 2008
    Messages : 1 606
    Points : 1 113
    Points
    1 113
    Par défaut
    Citation Envoyé par Montor Voir le message
    non cette strucrure est déja packer

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    TFileStruc = packed record
     data:array[0..23] of byte
    end;
    tu veut dire TFileSTrucList ? parcque TFileTruc est déjà déclaré, de plus TFileSTrucList n'ai même pas utilisé dans le programme que je mets 23 ou 100000 ou 0, où même que je retire tout le type cela ne change pas l'erreur de pointeur.

  7. #47
    Membre éprouvé
    Avatar de Montor
    Homme Profil pro
    Autre
    Inscrit en
    Avril 2008
    Messages
    879
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Avril 2008
    Messages : 879
    Points : 963
    Points
    963
    Par défaut
    tu veut dire TFileSTrucList ? parcque TFileTruc est déjà déclaré, de plus TFileSTrucList n'ai même pas utilisé dans le programme que je mets 23 ou 100000 ou 0, où même que je retire tout le type cela ne change pas l'erreur de pointeur.
    Citation Envoyé par montor
    il y aun octet qui indique la taille de chaine
    essaie
    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
     
     type
      TFileStruc =  record
        NumFact      : String;
        NumCompte    : String;
        Date         : String;
        FinLigne     : String;
      end;
      PFileBuff = ^TFileBuff;
      TFileBuff =  record
        Data:ARRAY[0..23] of char;
      end;
     
      function FileStruc(const ABin:TFileBuff):TFileStruc;
      begin
         with result,ABin do
         begin
          NumFact      := Copy(data,0,8);
          NumCompte    := Copy(data,9,9);
          Date         := Copy(data,18,6);
          FinLigne     := Copy(data,23,1);
         end;
      end;
     
     
    procedure TForm1.Button1Click(Sender: TObject);
    var
     s:string;
     h:TFileBuff;
     
    begin
       s:='FC000056411DEPTOU100207';
       h:=PFileBuff(PChar(S))^;
      with FileStruc(h) do
      ShowmessageFmt('%s'#10'%s'#10'%s'#10'%s'#10,
                      [NumFact,NumCompte,Date,FinLigne]
                    );
    end;

  8. #48
    Membre éprouvé
    Avatar de Dr.Who
    Inscrit en
    Septembre 2009
    Messages
    980
    Détails du profil
    Informations personnelles :
    Âge : 45

    Informations forums :
    Inscription : Septembre 2009
    Messages : 980
    Points : 1 294
    Points
    1 294
    Par défaut
    essai.txt est comme le fichier de 200mo ?


    parce que y'a un soucis :

    chaque ligne se termine par CRLF. donc 2 octets inattendus à la fin de la premiere ligne.

    donc la prochaine ligne ne serat pas a View+24 mais View+24+2!

    soit on travail en texte ... au quel cas on doit tout réadapter pour le texte, soit on travail en binaire donc exit les CR et autres LF.

    sans parler que CR LF c'est sous windows, on change de systeme (unixpar exemple) et paf ont à affaire à autre chose.

    comme ce serait anti-performant de devoir chercher le EOLn pour chaque ligne, il faut mettre les lignes bout à bout sans séparateur, on peut puisque chaque ligne est de la même taille donc, suppression de l'inutile.



    edit :

    exemple concret de recherche des factures emise le 10/02/2007.


    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
     
    uses
      FView;
     
    type
      // attention de bien mesurer la taille des chaines
      PFileStruct = ^TFileStruct;
      TFileStruct = packed record case integer of
        0 : ( Buffer : array[0..22] of AnsiChar);
        1 : (
              NumFact   : array[0..7] of AnsiChar; // 8
              NumCompte : array[0..8] of AnsiChar; // 9
              Date      : packed record case integer of
                0: (FullDate : array[0..5] of AnsiChar);
                1: (D,M,Y    : array[0..1] of AnsiChar); // 6
              end
              // CRLF : word; // au cas ou
            );
      end;
     
     
    const
      SizeOfFileStruct = SizeOf(TFileStruct);
     
     
    var
      FV : TFileView;
      Count : integer;
     
    procedure TForm12.FormCreate(Sender: TObject);
    var ptr : PFileStruct;
        N,C : integer;
        G   : cardinal;
    begin
      G := GetTickCount;
      C := 0;
     
      FV := TFileView.Create(ExtractFilePath(ParamStr(0))+'Datas.bin');
      try
        if FV.Loaded then
        begin
          Count := FV.FileSize div SizeOfFileStruct; 
          Ptr   := FV.View;
          for N := 0 to Count do // on n'enleve pas 1 
          begin
            if (Ptr^.Date.D = '10') and (Ptr^.Date.M = '02') and (Ptr^.Date.Y = '07') then
              inc(C);
            inc(ptr); // incremente directement à la prochaine donnée
          end;
        end;
      finally
        FV.Free;
      end;
     
      G := GetTickCount - G;
      caption := format('%d ms : %d facture le 10/02/07 sur %d factures',[G, C, Count+1]);
    end;
    torche les 175 milles entrées de datas.bin (fichiers de 3.83Mo) en moins de 47..63ms (HP Pavillion zv6000 complètement à l'ouest!)

    ce bout de code renverras une ligne dans le caption de la fiche :
    62 ms : 133712 facture le 10/02/07 sur 174929 factures

    est une bel fote sure "facture" eau seingeuliai.

    mon fichier test en pj, note que le fichier compréssé en Zip passe de prés de 4Mo à 12Ko!
    il y à la peut etre quelque chose d'interressant avec ZLib!

    note aussi que les String[] sont passé à array[] of AnsiChar. en effet on travail en Ansi et non en Unicode (delphi > 2007), cela evite les fastidieuse directive de compilation blablabla entre les vieux delphi et les nouveaux.

    note aussi que Delphi s'occupe à merveille de gerer les array of ansichar comme des chaines tout a fait normale (string ou ansistring) ce qui fait que cette fois on supprime totalement l'octet de taille de chaine en lecture et ecriture! donc plus d'erreur de ce coté.

    Il y a une options de compilation qui permet de gerer les chaines comme je le fait ici : la Syntaxe étendue.
    si cette option est désactivée le programme ne compilera plus.
    on peut la forcée avec : {$X+} ou {$EXTENDEDSYNTAX ON}
    par defaut le mode $X est activé il est rare qu'on désactive cette derniere car le code devient moins evident et moins intuitif à ecrire.

    dernier point, avec les array of char, il doivent etre obligatoirement indicé à partir de 0!
    Delphi les gère alors comme compatible avec PChar/PAnsiChar/PWideChar.

    un PChar est un pointeur sur un tableau array[0..n] of char.
    array[0..n] of char devient compatible avec un autre array[0..n] of char.
    ceci explique cela.
    par contre array[1..n] of char risque de ne pas l'etre puisqu' indexer à 1, mieux vaut ne pas tenter le test. on sait de toute façon qu'un bon développeur compte toujours à partir de 0.
    Fichiers attachés Fichiers attachés

  9. #49
    Membre éprouvé
    Avatar de Dr.Who
    Inscrit en
    Septembre 2009
    Messages
    980
    Détails du profil
    Informations personnelles :
    Âge : 45

    Informations forums :
    Inscription : Septembre 2009
    Messages : 980
    Points : 1 294
    Points
    1 294
    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
      TFileStruct = packed record case integer of
        0 : ( Buffer : array[0..22] of AnsiChar);
        1 : (
              NumFact   : array[0..7] of AnsiChar; // 8
              NumCompte : array[0..8] of AnsiChar; // 9
              Date      : packed record case integer of
                0: (FullDate : array[0..5] of AnsiChar);
                1: (D,M,Y    : array[0..1] of AnsiChar); // 6
              end
              // CRLF : word; // au cas ou
            );
      end;
    j'avoue que la structure devient un peu complexe, mais en lisant bien, on remarque qu'elle est relativement simple et surtout pratique.

    note bien comme je transforme "Date" en FullDate aligné sur D,M,Y.
    ce la permet d'avoir d'une par
    100207 par exemple
    et d'acceder facilement au jours, mois et année sans passer par des copy ou autre...

    cela est identique pour l'alignement des champs avec Buffer.
    Buffer permet d'afficher d'un coups toute la ligne.

    on pourrait encore separer NumFact en 2 pour separer le numero de "FC"

    NumFact : packed record case integer of
    0: (FullNum : array[0..7] of AnsiChar);
    1: (FC : array[0..1] of AnsiChar, Num: array[0..5] of AnsiChar);
    end


    attention, il ne faut pas en abuser non plus.

  10. #50
    Membre éprouvé Avatar de BuzzLeclaire
    Homme Profil pro
    Dev/For/Vte/Ass
    Inscrit en
    Août 2008
    Messages
    1 606
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Dev/For/Vte/Ass

    Informations forums :
    Inscription : Août 2008
    Messages : 1 606
    Points : 1 113
    Points
    1 113
    Par défaut
    Alors,

    Dr Who : le fichier txt n'est pas concaténé, il y a bien à chaque fin de ligne un retour chariot (je rappel que je ne suis pas l'auteur du fichier, je dois l'utiliser tel quel)

    Voici l'unit, suite à tes dernières remarques et suggestions, au passage le coup de la date pas mal !!! ou autre packed records...

    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
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    unit Unit1;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, FView;
     
    type
      TForm1 = class(TForm)
        Button1: TButton;
        ListBox1: TListBox;
        procedure Button1Click(Sender: TObject);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
      type
      PFileStruc = ^TFileStruc;
      TFileStruc = packed record case integer of
        0 : ( Buffer : array[0..23] of AnsiChar);
        1 : (
              NumFact   : array[0..7] of AnsiChar; // 8
              NumCompte : array[0..8] of AnsiChar; // 9
              DateEcr   : packed record case integer of
                0: (FullDate : array[0..5] of AnsiChar);
                1: (D,M,Y    : array[0..1] of AnsiChar); // 6
              end;
              FinLigne  : array[0..1] of AnsiChar;
            );
      end;
     
    const
      SizeOfFileStruc = SizeOf(TFileStruc);
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    procedure TForm1.Button1Click(Sender: TObject);
    var
      FV : TFileView;
      PFS : PFileStruc;
      Count, N : integer;
      list : Tlist;
      FS: TFileStruc;
      TGV: Cardinal;
    begin
      TGV := GetTickCount;
     
      FV := TFileView.Create('C:\essai\essai.txt');
      list := Tlist.Create;
      try
        if FV.Loaded then
        begin
          PFS := FV.View; // on lit PFileStruc par PFileStruc
          showmessage(
          'Taille Structure = '+inttostr(SizeOfFileStruc)+ #13+#10+
          'FileSize = '+Inttostr(FV.FileSize)+ #13+#10 +
          'Count = ' + inttostr((FV.FileSize) div SizeOfFileStruc)
          );
          Count := ((FV.FileSize) div SizeOfFileStruc); // nombre d'elements
          for N := 0 to count-1 do
          begin
            List.Add(Pointer(integer(FV.View) + (SizeOfFileStruc*N)));
          end;
        end;
        for n := 0 to List.Count - 1 do
        Begin
          FS := PFileStruc(List.Items[n])^;
    //      Showmessage('NumFact = ' + FS.DateEcr.Y);
        End;
     
      finally
        FV.Free;
      end;
      TGV := GetTickCount - TGV;
      showmessage(floattostr(TGV));
    end;
     
     
    end.
    Alors j'ai fais un test avec un fichier de 70 Mo, c'est hallucinant la vitesse de traitement au moins 10 fois plus rapide que l'utilisation d'un TMemoryStream.

    La notion de structure est vraiment un atout incontournable. Maintenant je dois alimenter FS.NumCompte dans une colonne de StringGrid, j'ai fais des tests via un TStringList... hmmmm sa ram... (enfin sur un fichier de 70 Mo), mais avant cela je doit impérativement épurer les doublons du Tlist

    Mes questions :
    - existe-t-il un fonction toute faite sur les occurences de Tlist pour éviter les doublons ? (tout en sachant que Tlist ne référence que des pointeurs).
    - 0 : ( Buffer : array[0..23] of AnsiChar); cela sert à quoi cette ligne ? (je me coucherais moins bête).
    - PFS := FV.View; // on lit PFileStruc par PFileStruc cela sert à quoi puisque je n'utilise pas FPS ?

    Montor : Merci pour ta correction, qui m'a éclairé pour la suite.

    @+

  11. #51
    Membre éprouvé Avatar de BuzzLeclaire
    Homme Profil pro
    Dev/For/Vte/Ass
    Inscrit en
    Août 2008
    Messages
    1 606
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Dev/For/Vte/Ass

    Informations forums :
    Inscription : Août 2008
    Messages : 1 606
    Points : 1 113
    Points
    1 113
    Par défaut Ajout anti-doublons
    Un précision d'utilisation par rapport à l'unité si-dessus.

    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
    74
    75
    76
    77
    78
    79
    80
    81
    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, FView;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        ListBox1: TListBox;
        procedure Button1Click(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
    
      type
      PFileStruc = ^TFileStruc;
      TFileStruc = packed record case integer of
        0 : ( Buffer : array[0..23] of AnsiChar);
        1 : (
              NumFact   : array[0..7] of AnsiChar; // 8
              NumCompte : array[0..8] of AnsiChar; // 9
              Date      : packed record case integer of
                0: (FullDate : array[0..5] of AnsiChar);
                1: (D,M,Y    : array[0..1] of AnsiChar); // 6
              end;
              FinLigne  : array[0..1] of AnsiChar;
            );
      end;
    
    const
      SizeOfFileStruc = SizeOf(TFileStruc);
    
    var
      Form1: TForm1;
      ListString: TStringList;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.Button1Click(Sender: TObject);
    Var
      n: Integer;
    Begin
        for n := 0 to ListString.Count - 1 do
        Begin
          Showmessage('NumFact = ' + ListString.Strings[n]);
        End;
    end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    var
      FV : TFileView;
      Count, N : integer;
      FS: TFileStruc;
    begin
      FV := TFileView.Create('C:\essai\essai.txt');
      ListString := TStringList.Create;
      try
        if FV.Loaded then
        begin
          Count := ((FV.FileSize) div SizeOfFileStruc); // nombre d'elements
          ListString.Duplicates := dupIgnore;
          ListString.Sorted := true;
          for N := 0 to count-1 do
          begin
            ListString.Add(PFileStruc(Pointer(Integer(FV.View) + (SizeOfFileStruc*N)))^.NumCompte);
          end;
        end;
      finally
        FV.Free;
      end;
    
    end;
    end.
    Comme je ne suis intérésse que par les données j'envoi directe les données pointé dans une Stringlist :

    ListString.Add(PFileStruc(Pointer(Integer(FV.View) + (SizeOfFileStruc*N)))^.NumCompte);


    @+

    [EDIT]
    et avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
          ListString.Duplicates := dupIgnore;
          ListString.Sorted := true;
    en plus dans le code, je suis tranquille en terme de gestion de doublons...

  12. #52
    Membre éprouvé
    Avatar de Montor
    Homme Profil pro
    Autre
    Inscrit en
    Avril 2008
    Messages
    879
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Avril 2008
    Messages : 879
    Points : 963
    Points
    963
    Par défaut
    je ne sais pas pouquoi Dr.Who aime compliquer les chose voici un class qui permet la lecture/ecriture des pages directement sur le fichier
    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
      TIndexedFile=class(TFileStream)
       private
         FOffset   :integer;
         FPageSize :integer;
         FBuffer   :array of byte;
         function PageToPos(Aidx:integer):integer;
         function Get_Page(idx:integer):Pointer;
         function Get_Count():integer;
         procedure Set_Page(idx:integer;ABuff:Pointer);
       public
         constructor Create(const AFilename:string;APageSize:integer);
         property Pages[index:integer]:Pointer read Get_Page write Set_Page ;default;
         property Offset:integer read FOffset write FOffset;
         property Count:integer read Get_Count;
       end;
     
    implementation
     
    constructor TIndexedFile.Create(const AFilename:string;APageSize:integer);
    begin
       if (APageSize < 16) or  (APageSize > 8192) then
         raise Exception.Create('error');
       inherited Create(AFilename,fmOpenReadWrite);
       FPageSize := APageSize;
       SetLength(FBuffer,APageSize);
    end;
     
    function TIndexedFile.PageToPos(Aidx:integer):integer;
    begin
         result:= (Aidx * FPageSize)+FOffset;
         if (result >= Size) then
          raise Exception.Create('error');
    end;
     
    function TIndexedFile.Get_Count():integer;
    begin
        result:= Size div FPageSize;
    end;
     
    function TIndexedFile.Get_Page(idx:integer):Pointer;
    begin
       Seek(PageToPos(idx),soBeginning);
       if Read(Pointer(FBuffer)^,FPageSize)=FPageSize then
        result:=FBuffer
         else
          raise Exception.Create('error');
    end;
     
    procedure TIndexedFile.Set_Page(idx:integer;ABuff:Pointer);
    begin
       Seek(PageToPos(idx),soBeginning);
       Write(Pointer(ABuff)^,FPageSize);
    end;
    end.
    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
    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
     
      PFileStruc = ^TFileStruc;
      TFileStruc = record
        NumFact      : String;
        NumCompte    : String;
        Date         : String;
        FinLigne     : String;
      end;
     
      PFileBuff = ^TFileBuff;
      TFileBuff =  record
        Data:array[0..23] of AnsiChar;
      end;
     
     function FileStruc(AP:PFileBuff):TFileStruc;
     const
     WORK_CONST = 24;
     
    var
      Form1: TForm1;
      d:TIndexedFile;
    implementation
     
    {$R *.dfm}
    function FileStruc(AP:PFileBuff):TFileStruc;
    begin
        with result,AP^ do
        begin
          NumFact      := Copy(Data,0,8);
          NumCompte    := Copy(Data,9,9);
          Date         := Copy(Data,18,6);
          FinLigne     := Copy(Data,23,1);
        end;
    end;
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
       d:=TIndexedFile.Create('C:\Data',WORK_CONST);
    end;
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
     
    showmessagefmt( 'Count:%d'#10
                   +'Size :%d'#10,
                     [d.Count,d.Size]);//Count nombre de pages
     
     
    with FileStruc(d.Pages[1]) do //d.Pages[2]<--index de page
      ShowmessageFmt('%s'#10'%s'#10'%s'#10'%s'#10,
                      [NumFact,NumCompte,Date,FinLigne]
                    );
     
    end;
     
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
    d.Free
    end;
    épurer les doublons du Tlist
    utilise un TStringList sorted a true il y a une autre parametre...

    - existe-t-il un fonction toute faite sur les occurences de Tlist pour éviter les doublons ? (tout en sachant que Tlist ne référence que des pointeurs).
    IL Y A le superb INIFILE TStringHash;
    il y a bien à chaque fin de ligne un retour chariot
    pour cette raison j'ai envoyé dans une poste precedante

  13. #53
    Membre éprouvé Avatar de BuzzLeclaire
    Homme Profil pro
    Dev/For/Vte/Ass
    Inscrit en
    Août 2008
    Messages
    1 606
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Dev/For/Vte/Ass

    Informations forums :
    Inscription : Août 2008
    Messages : 1 606
    Points : 1 113
    Points
    1 113
    Par défaut
    Citation Envoyé par Montor Voir le message
    utilise un TStringList sorted a true il y a une autre parametre...
    Regarde mon dernier post, c'est exctement ce que j'ai fais.

    Le dernier Unit que j'ai mis est vraiment pas mal non ?

  14. #54
    Membre éprouvé
    Avatar de Montor
    Homme Profil pro
    Autre
    Inscrit en
    Avril 2008
    Messages
    879
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Avril 2008
    Messages : 879
    Points : 963
    Points
    963
    Par défaut
    Le dernier Unit que j'ai mis est vraiment pas mal non ?
    ne pas oublier BeginUpdate,EndUpdate;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ListString.BeginUpdate();
    try
          for N := 0 to count-1 do
            ListString.Add(PFileStruc(Pointer(Integer(FV.View) + (SizeOfFileStruc*N)))^.NumCompte);
    finally   
      ListString.EndUpdate();
    end;

  15. #55
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Bonjour,

    Pendant que vous explorez votre piste j'ai modifié CopyFragFiles pour répondre à la question :

    Ou alors récupérer les deux info copyfragFiles(,,,[NumFactures,NumCompte]) ?
    Voici la nouvelle version où je supprime tous les intermédiaires (tMemoryStream, SCumul:=SCumul+S; listString, et RichEdit.lines.SaveToFile) qui bouffent chacun du temps et où je copie directement les fragments du FileStream-Source dans le FileStream-Destination :

    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
    function CopyAndSaveFragsFile(const FileNameSource,FileNameDest : String) : longint;
    //       Copie des fragments de FileNameSource dans FileNameDest
    //       Renvoie le nombre de lignes de FileNameDest
    //       Utilisable pour des fichiers-sources structurés comme suit :
    //       '---ABCDEFGHIJ----------123456789------------987654----#13#10'
    //       '---BYUJOLMPGF----------284569752------------358796----#13#10'
    //       ici les '-' représentent les parties indésirables et le reste les fragments à récupérer
    //       Structure du fichier de destination :
    //       'ABCDEFGHIJ123456789987654#13#10
    //       'BYUJOLMPGF284569752358796#13#10
    //       Pour fichiers-source de taille inférieure à 2 Go.
    const    pos1 =  3; size1 = 10; //<- Positions et tailles de chaque fragment à
             pos2 = 23; size2 =  9; //   récupérer dans chaque ligne du fichier-source.
             pos3 = 44; size3 =  6;
             pos4 = 75; size4 =  7;
             pos5 =113; size5 =  9;
             Pas  =124; // Pas dépendant de la Longueur d'une ligne du fichier-source.         CRLF = #13#10;
    var      FS : tFileStream; // Fichier-Source
             FD : tFileStream; // Fichier-Destination
             from1,from2,from3,from4,from5,po : integer;
             SizeFiSource : integer;
    begin    Result:=0;
    
             if (not FileExists(FileNameSource)) then
             begin Showmessage('Fichier '+FileNameSource+' : inexistant'); EXIT; end;
             try FS := TFileStream.create(FileNameSource, fmOpenRead or fmShareDenyWrite);
                 FD := TFileStream.create(FileNameDest, fmCreate);
                 SizeFiSource:=FS.size;
                 from1:=pos1; from2:=pos2; from3:=pos3; from4:=pos4; from5:=pos5;
                 repeat // Copie du 1er fragment :
                       FS.Position := from1;
                       if FS.Position>=SizeFiSource then Break;
                       FD.CopyFrom(FS, size1);
    
                       // Copie du 2ième fragment :
                       FS.Position := from2;
                       FD.CopyFrom(FS, size2);
    
                       // Copie du 3ième fragment :
                       FS.Position := from3;
                       FD.CopyFrom(FS, size3);
    
                       // Copie du 4ième fragment :
                       FS.Position := from4;
                       FD.CopyFrom(FS, size4);
    
                       // Copie du 5ième fragment :
                       FS.Position := from5;
                       FD.CopyFrom(FS, size5);
                       FD.write(PChar(CRLF)^,2); // Ajout du CRLF de fin de ligne
    
                       // Calcul des from pour la ligne suivante :
                       inc(from1,Pas); inc(from2,pas); inc(from3,Pas);
                       inc(from4,Pas); inc(from5,pas);
                       inc(Result);
                 until From1 >= SizeFiSource;
             finally
                 FS.Free;
                 FD.Free
             end;
    end;
    ... en vert ci-dessus les constantes à modifier en fonction de la position et de la taille et du nombre des fragments à récupérer dans chaque ligne du fichier-source. Toute l'étape de copiage est encapsulée dans cette function.

    Exemple d'utilisation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    procedure TForm1.bCopAndSaveClick(Sender: TObject);
    var       nb : longint; fiSource,fiDest : string;
    begin     fiSource :=ExtractFilePath(Application.ExeName)+'TestLigs125.txt';
              fiDest   :=ExtractFilePath(Application.ExeName)+'TestLigsFrag.txt';
              nb:=CopyAndSaveFragsFile(fiSource,fiDest);
              RichEdit2.Lines.LoadFromFile(fiDest);
              RichEdit2.Lines.Add('nb Lignes = '+intToStr(nb));
    end;
    A+.

  16. #56
    Membre éprouvé
    Avatar de Montor
    Homme Profil pro
    Autre
    Inscrit en
    Avril 2008
    Messages
    879
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Avril 2008
    Messages : 879
    Points : 963
    Points
    963
    Par défaut
    Filestream n'est pas comme memorystram L'utilisation un Buffer de petite taille n'est bon if faut lire touts la structure ou plusieurs pour gagner des performances

  17. #57
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Re-bonjour,

    L'utilisation un Buffer de petite taille n'est bon if faut lire touts la structure ou plusieurs pour gagner des performances
    ... je n'ai pas utilsé de Buffer puisque je copie directement depuis le FileStream-Source vers le FileStream-Destination sans passer par aucun intermédiaire.

    A titre indicatif voici les durées d'execution issus de deux tests :

    CopyAndSaveFragsFile : mis 2437 ms
    nb Lignes = 84564
    Taille Fichier-source = 10 Mo
    Taille Fichier-destin = 3,468 Mo
    CopyAndSaveFragsFile : mis 24797 ms
    nb Lignes = 845628
    Taille Fichier-source = 100 Mo
    Taille Fichier-destin = 34,678 Mo
    25 secondes pour 100 Mo donc moins d'une minute pour 200 Mo sous Pentium III à 1,13 GHz.

    A+.

  18. #58
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 708
    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 708
    Points : 25 590
    Points
    25 590
    Par défaut
    Bon, j'ai survolé le sujet, semble que ce soit un fichier à longueur fixe, la solution de Dr.Who est très pertinente, en se servant du record comme moyen de lire le fichier directement (packed record, array au lieu de string ...)
    Le Gros avantage c'est que l'on pas une succession de Copy qui s'avère pénible à maintenir si la structure évolue ...

    Regarde ce sujet affectation String et Record, c'est très très ressemblant à la problèmatique évoqué !

    Ainsi que ce sujet pour utiliser plutôt le transtypage de record que les structures variables ...

  19. #59
    Membre éprouvé Avatar de BuzzLeclaire
    Homme Profil pro
    Dev/For/Vte/Ass
    Inscrit en
    Août 2008
    Messages
    1 606
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Dev/For/Vte/Ass

    Informations forums :
    Inscription : Août 2008
    Messages : 1 606
    Points : 1 113
    Points
    1 113
    Par défaut
    Salut,

    Je te rejoint ShailLeTroll, la maintenance est moins facile, et de plus j'obtiens un autre fichier, il faut ensuite que je l'envoi dans un tringlist pour élliminé les doublons. Ceci dit cela fonctionne également.

    Ma problèmatique principale et largement comblée par toutes vos idées que ce soit les éclaircissement de Montor la gestion de FMemoryStream ou TFileStream de Gilbert ou l'avancée en terme de mise en place par Dr. Who qui au final me permet de répondre à mon problème.

    Mais ce n'ai pas le dernier problème, je vais m'inspirer des liens de Shail, car maintenant je doit m'attaquer à une autre structure (toujours imposée) qui comporte des balises de début et fin et entre chaque balise une structure presque identique à celle-ci.

    Mais pour le moment je vous remercie tous, car vous êtes vraiment

    DES BETES DE COURSES



    [EDIT]

    A oui il me restait 1 p'tite chose

    ( Buffer : array[0..23] of AnsiChar); cela sert à quoi cette ligne ? (je me coucherais moins bête).

  20. #60
    Membre éprouvé
    Avatar de Dr.Who
    Inscrit en
    Septembre 2009
    Messages
    980
    Détails du profil
    Informations personnelles :
    Âge : 45

    Informations forums :
    Inscription : Septembre 2009
    Messages : 980
    Points : 1 294
    Points
    1 294
    Par défaut
    Pas le temps de repondre à tout,

    @Montor : je rejoins Shay pour dire que TFileStream, TMemoryStream, ou autre truc à base de blocread/blocwrite etc sont trop long.

    L'avantage de travailler avec une vue du fichier, on est sur un pointeur, plutot que d'avoir plusieurs instruction de seek, de position, de copy etc, on as que de simple inc sur le pointeur.
    et on le vois bien sur les test de perf :

    lecture et ecriture dans ton code ?
    34 350 St/sec et environ 4.3Mo/s de TT moyen.

    de mon coté j'affiche (lecture uniquement) :
    1 240 631 St/sec et environ 27Mo/s TT au min
    2 821 436 St/sec et environ 62Mo/s TT au max (?)
    et encore, n'étant pas un spécialiste du filemapping je pense qu'il y'a moyen de mieux le mettre en œuvre.

    TStream, TStrings, c'est bien pour de la petite données, des trucs de moins d'1Mo ou du milliers d'item.
    Mais quand on commence à aller dans les gros chiffres, qu'on depasse les dizaines de Mo et les centaines de milliers d'item ... faut sortir l'artillerie lourde.
    Il est certains qu'il vaut mieux ne pas tenter de tuer une mouche avec un tank, mais prendre un bazooka pour descendre un Boss elite Level 200 en mode épique ça se justifie.

    de plus, rien n'empeche le bazooka de tuer la mouche egalement.
    bon au passage faudra penser à refaire le salon et racheter des rideaux ... et des murs ... mais bon ... c'est secondaire.




    Citation Envoyé par BuzzLeclaire Voir le message
    ( Buffer : array[0..23] of AnsiChar); cela sert à quoi cette ligne ? (je me coucherais moins bête).
    Buffer est superposé à la structure inferieure, donc Buffer contient une chaine qui représente la donnée "complete".
    note bien qu'on peut exclure le CRLF de Buffer, superposer des données n'oblige pas à respecter la taille de ces dernières, la structure prendra l'ensemble de données qui à la taille la plus grande pour definir sa propre taille.

    on peu trés bien faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    untruc = record case integer of
      0 : (color : integer); // 4 octets
      1 : (R,G,B: byte); // 3 octets
    end;
    taille de "untruc" = 4 octets.

    (hop, comment s'exempter d'utiliser shl, shr et et autre GetXValue pour avoir le RGB d'une couleur).

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Demande de conseil pour migration de lignes vers colonnes
    Par ririd dans le forum Administration
    Réponses: 6
    Dernier message: 04/11/2004, 18h02
  2. [Struts_Tiles VS CSS] Demande de Conseils
    Par sylvain_neus dans le forum Struts 1
    Réponses: 4
    Dernier message: 16/04/2004, 11h12
  3. [sqlbaseserver]demande de conseils/aides pour requêtes
    Par GéniuS77 dans le forum Langage SQL
    Réponses: 14
    Dernier message: 18/03/2004, 18h27
  4. demande de conseil
    Par stephane eyskens dans le forum EDI/Outils
    Réponses: 2
    Dernier message: 25/09/2003, 15h18

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