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 :

Partir d'un gros fichier pour en faire plusieurs petits


Sujet :

Delphi

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    624
    Détails du profil
    Informations personnelles :
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 624
    Points : 199
    Points
    199
    Par défaut Partir d'un gros fichier pour en faire plusieurs petits
    Bonjour à tous,

    j'ai un très gros fichier XML (550Mo) que je n'arrive pas à ouvrir avec omniXML car trop volumineux. Je voudrais l'éclater en plusieurs petits morceaux.

    Le fichier a une structure de ce type:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    <a>
      <b>
      </b>
    </a>
    <a>
      <b>
      </b>
    </a>
    <a>
      <b>
      </b>
    </a>
    etc..
    J'ai essayé avec ma fonction habituelle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    x:=PChar(sPage);
    While Scan('<a>', '</a>', x, s) and (s<>'') do
    Begin
          s:='<a>'+s+'</a>';
          ....
    End;
    Mais hélas j'ai droit à un beau message "Out of Memory"

    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
     
    function Scan(const Search1, Search2: string; var Ch: PChar; var Text: string): Boolean;
    var
      i: Integer;
    begin
      Result:=False;
      if not Assigned(Ch) then
        Exit;
      i:=Pos(Search1, Ch)-1;
      if (i>=0) then
      begin
        Ch:=Ch+i+Length(Search1);
        i:=Pos(Search2, Ch)-1;
        if (i>=0) then
        begin
          Text:=Copy(Ch, 1, i);
          Ch:=Ch+i+LEngth(Search2);
        end
        else
        begin
          Text:=StrPas(Ch);
          Ch:=nil;
        end;
        Result:=True;
      end;
    end; {* func Scan *}
    Auriez vous une fonction/Procedure pour me venir en aide ?
    Ou alors m'aider à trouver pourquoi elle provoque un "Out of Memory" ?

    Amicalement,
    Bruno

  2. #2
    Membre expérimenté
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    2 437
    Détails du profil
    Informations personnelles :
    Âge : 71
    Localisation : Belgique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 2 437
    Points : 1 328
    Points
    1 328
    Par défaut
    @ Bruno13, regarde un peux ce lien :

    http://big.developpez.com/delphi/xml/msxml/#LII

    @+,

    Cincap

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    624
    Détails du profil
    Informations personnelles :
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 624
    Points : 199
    Points
    199
    Par défaut
    Salut Cincap,

    Comme omniXML est basé sur lui, est-ce qu'il sait gérer les gros fichiers car je rappelle que mon problème à l'origine provient du fait que le fichier source xml fait plus de 550Mo

  4. #4
    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,

    A première vue ton fichier a une structure répétitive donc la taille de chaque morceau devrait être la même (sauf peut-etre le premier) mais si tu connais la postion du début de chaque morceau et sa taille tu peux essayer avec :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function CopyFragFile(const FileName : String; From,SizeFrag : longint) : tMemoryStream;
    //       Renvoie un MemoryStream contenant la copie d'un fragment d'un fichier à
    //       partir de la position From et de taille SizeFrag octets
    var      FS : tFileStream;
    begin    Result:=tMemoryStream.create;
             if (not FileExists(FileName)) then
             begin Showmessage('Fichier '+FileName+' : inexistant'); EXIT; end;
             FS := TFileStream.create(FileName, fmOpenRead or fmShareDenyWrite);
             FS.Position := From;
             Result.CopyFrom(FS, SizeFrag);
             Result.Position:=0;
             FS.Free;
    end;
    Comme cette routine utilise un FileStream il suffit que le morceau renvoyé sous forme de MemoryStream tienne dans la mem-vive-disponible pour éviter le message "Out of Memory".

    A+.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    624
    Détails du profil
    Informations personnelles :
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 624
    Points : 199
    Points
    199
    Par défaut
    Salut Gilbert,

    Hélas entre mes balises <b> et </b> j'ai du texte libre donc impossible pour moi de connaître la taille exacte.

    De plus, dans ma fonction Scan, dès le premier passage sur la ligne:

    Text:=Copy(Ch, 1, i);

    j'ai le out of memory qui arrive. Pourtant i = 764998 tout le temps à chaque exécution et Ch pointe bien sur du texte. J'ai même essayé de mettre i à 750 pour voir et là aussi ça plante :'(

  6. #6
    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,

    Hélas entre mes balises <b> et </b> j'ai du texte libre donc impossible pour moi de connaître la taille exacte.
    ... ben si avant le découpage en morceaux, tu lis le TFileStream pour mémoriser dans un array les positions des balises </b> la taille de chaque morceau sera égale à PositionDuSuivant moins PositionDuPrécédent. OUI/non ?

    A+ .
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    624
    Détails du profil
    Informations personnelles :
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 624
    Points : 199
    Points
    199
    Par défaut
    Là on retombe pas sur le problème du Pos ?

    je suis étonné de me prendre autant la tête pour faire ce genre du truc
    Nostalgique du bon vieux Perl

  8. #8
    Membre habitué
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    624
    Détails du profil
    Informations personnelles :
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 624
    Points : 199
    Points
    199
    Par défaut
    Bonjour à tous,

    je fais profiter de la réponse que l'on m'a donné ailleurs. Voici la fonction qui gère les très gros volume:

    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
    function Scan(const Search1, Search2: string; var Ch: PChar; var Text: string): Boolean;
    var
      Ch1, Ch2: PChar;
    begin
      Result:=False;
      if not Assigned(Ch) then
        Exit;
      Ch1 := StrPos(Ch, PChar(Search1));
      if Ch1 <> nil then
      begin
        Ch := Ch1 + Length(Search1);
        Ch2 := StrPos(Ch, PChar(Search2));
        if Ch2 <> nil then
        begin
          SetString(Text, Ch, Ch2 - Ch);
          Ch := Ch2 + Length(Search2);
        end
        else
        begin
          Text := StrPas(Ch);
          Ch := nil;
        end;
        Result := True;
      end;
    end; {* func Scan *}
    Explication:

    > i:=Pos(Search1, Ch)-1;
    > > i:=Pos(Search2, Ch)-1;
    > > Text:=Copy(Ch, 1, i);

    ces 3 fonctions prennent des "string" comme paramètres, Delphi doit
    transtyper le PChar(Ch) and string et donc allouer la quantité de mémoire
    correspondante pour stocker la valeur chaîne contenue dans Ch sous la
    forme d'une string.

    > > Text:=StrPas(Ch);

    comme l'a dit Obones, me semble que les fonctions commençant par Str*
    prennent des PChar en paramètres, donc StrPos devrait pouvoir remplacer
    les appels à Pos. Pour remplacer Copy, il faut regarder du coté de
    SetString il me semble.

    > > Auriez-vous une idée du pourquoi ?

    parce que passer de string en pchar est rapide et sans allocation de
    mémoire, par contre l'opération inverse est très gourmande en temps (il
    faut copier) et en allocation. le type PChar est bien adapté aux gestions
    rapides "bas-niveau" des chaînes de caractères si il n'y a pas de
    repassage en string.

  9. #9
    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,

    Je ne pige pas bien le fonctionnement de la fonction Scan, et ça me chagrine

    function Scan(const Search1, Search2: string; var Ch: PChar; var Text: string): Boolean;
    D'après :
    While Scan('<a>', '</a>', x, s) and (s<>'') do
    il apparaît que Search1, Search2 sont les balises '<a>', '</a>',
    ... par contre à quoi correspond 'Ch' qui vaut ici x ???
    ... et Text qui vaut ici 's' c'est le texte complet du fichier de 550 Mo ???

    A+.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  10. #10
    Membre habitué
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    624
    Détails du profil
    Informations personnelles :
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 624
    Points : 199
    Points
    199
    Par défaut
    Bonjour Gilbert,

    Alors cette fonction permet d'extraire le texte qui se trouve entre "Search1" et "Search2" pour le placer dans la variable "Text". Ch sert à parcourir la chaine origine (ici "sPage").

    Est-ce plus clair ?

    Amicalement,
    Bruno

  11. #11
    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 Bruno,

    Alors cette fonction permet d'extraire le texte qui se trouve entre "Search1" et "Search2" pour le placer dans la variable "Text". Ch sert à parcourir la chaine origine (ici "sPage").

    Est-ce plus clair ?
    ... OK, merci, comme ça je pige mieux, je craignais que "Text" c'était les 550 Mo donc "sPage" est une fraction de taille arbitraire des 550 Mo.

    ... Mais dans ce cas, si le début de sPage contient par exemple :
    "Tagada ... TrucMuche""Search1"Suite du texte""Search2"
    tu risques de perdre le "Tagada ... TrucMuche" qui ne se trouve pas entre un "Search1" et un "Search2"
    ... et idem si la fin de sPage ne se termine pas par un "Search2".

    Si c'est le cas je te suggère plutôt d'utiliser la routine :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    function SearchStringInBigFile(const FileName, SearchString: string; out OffSets: TIntegerDynArray; KeepOffSet: Boolean = False; Threshold: Integer = MaxInt; CaseSensitive: Boolean = True; AcceptOverlap: Boolean = False): Integer;
    de ShaiLeTroll
    dans laquelle "SearchString" c'est "Search1" puis dans un deuxième temps "Search2" et dont l'array "OffSets" te renvoie le relevé topographique des positions de début de tous les "Search1" puis de tous les "Search2"
    et ensuite tu peux utliser la function CopyFragFile(const FileName : String; From,SizeFrag : longint) : tMemoryStream ainsi tu ne perdra rien du texte.

    Le "From" ci-dessus sera égal OffSets[i]+length(Search1)
    Le "SizeFrag" ci-dessus sera égal à OffSets[i+1] - OffSets[i] - length(Search1) - length(Search2).

    Cordialement, et à +.

    P.S : Pour trouver le code de SearchStringInBigFile : utiliser la fonction Rechercher du Forum avec une partie raccourcie du nom car il est trop long.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  12. #12
    Membre habitué
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    624
    Détails du profil
    Informations personnelles :
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 624
    Points : 199
    Points
    199
    Par défaut
    Salut Gilbert,

    ... Mais dans ce cas, si le début de sPage contient par exemple :
    "Tagada ... TrucMuche""Search1"Suite du texte""Search2"
    tu risques de perdre le "Tagada ... TrucMuche" qui ne se trouve pas entre un "Search1" et un "Search2"
    Pourquoi est-ce que "Tagada ... TrucMuche" m'intéresserai ? puisque je cherche uniquement "Suite du texte" ??

  13. #13
    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,

    Pourquoi est-ce que "Tagada ... TrucMuche" m'intéresserai ? puisque je cherche uniquement "Suite du texte" ??
    ... parceque "Tagada ... TrucMuche" représente ici la fin d'un texte présent dans sPage et que le début du texte en question se trouve dans le sPage traité précédemment : cas d'un texte à cheval sur deux sPage car je suppose que la taille des sPage est une fraction de taille arbitraire du texte complet de 550 Mo puisque tu ne parles plus du "OutOfMemory".

    C'est comme si tu cherchais le mot Tartanpion dans deux strings successives :
    - s[i]:='sldkjslk ... Tartan';
    - s[i+1]:='pion ... amkljzj';

    Vu ?

    Cordialement et à +.
    ives
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

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

Discussions similaires

  1. Manipulation de 2 fichiers pour en faire un seul
    Par tetzispa dans le forum Shell et commandes GNU
    Réponses: 14
    Dernier message: 04/03/2014, 13h16
  2. Réponses: 16
    Dernier message: 03/05/2012, 14h22
  3. Réponses: 8
    Dernier message: 15/07/2008, 17h41
  4. Réponses: 4
    Dernier message: 27/09/2007, 15h05
  5. générer un fichier xml à partir d'un gros fichier plat
    Par ybennani dans le forum Format d'échange (XML, JSON...)
    Réponses: 7
    Dernier message: 16/05/2007, 10h47

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