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 :

Ajouter une chaîne de caractères au début d'un fichier texte rempli


Sujet :

Delphi

  1. #1
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2012
    Messages
    97
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2012
    Messages : 97
    Points : 59
    Points
    59
    Par défaut Ajouter une chaîne de caractères au début d'un fichier texte rempli
    Bonjour les amis,

    je voudrais savoir quel est le meilleur composant Delphi qui me permet d'insérer une ligne tout au début d'un fichier texte contenant du texte.
    Ps: j'ai pu insérer une chaîne de caractères à la fin du fichier texte en utilisant un Ttextfile

    Merci d'avance !

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 447
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    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 447
    Points : 24 849
    Points
    24 849
    Par défaut
    Il n'y a pas spécialement de composant, le plus simple un TStream et un fichier temporaire

    - TFileStream Temp sur un fichier temporaire (creation)
    - Write du Buffer à mettre au début
    - TFileStream Ex sur le fichier existant (lecteur seule)
    - Copy de Stream Ex vers Temp (lecture tamponée à 32Ko)
    - Cloture du stream Ex
    - Cloture du Stream Temp
    - Renommage du fichier Ex en Archive
    - Renommage du fichier Temp en Ex
    - Nettoyage du fichier Archive

    Récemment, j'ai fait cela lors d'un passage de D7 à D10, avec de tout petit fichier log, je suis reparti d'une fonction en D7, j'ai tout mis dans une chaine, je manipule la chaine et je réécris tout, c'est moche mais pour un petit fichier ça passe.

    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
    function xxxLoadFromFile(const AFileName: string): string;
    var
      VFileStream: TFileStream;
      VSize: Integer;
      VPreamble: TBytes;
      VPreambleSize: Integer;
      VEncoding: TEncoding;
      VMemStream: TBytesStream;
    begin
      if not FileExists(AFileName) then
        Exit('');
     
      VFileStream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite) ;
      try
        SetLength(VPreamble, 4); // 2 pour UTF-16, 3 pour UTF-8 et 4 pour UTF-32
        VPreambleSize := VFileStream.Read(VPreamble, 4);
        if VPreambleSize >= 2 then
        begin
          VEncoding := nil;
          VPreambleSize := TEncoding.GetBufferEncoding(Copy(VPreamble, 0, VPreambleSize), VEncoding, TEncoding.ANSI);
          VSize := VFileStream.Size - VPreambleSize;
        end
        else
        begin
          VEncoding := TEncoding.ANSI;
          VPreambleSize := 0;
          VSize := VFileStream.Size;
        end;
     
        VFileStream.Seek(VPreambleSize, soBeginning);
     
        VMemStream := TBytesStream.Create();
        try
          VMemStream.CopyFrom(VFileStream, VSize);
          Result := VEncoding.GetString(VMemStream.Bytes, 0, VSize);
        finally
          VMemStream.Free();
        end;
      finally
        VFileStream.Free;
      end;
    end ;
     
    procedure xxxSaveToFile(const AFileName: string; const AContent: string; AEncoding: TEncoding = nil);
    var
      VFileStream: TFileStream;
      VPreamble: TBytes;
      VMemStream: TStringStream;
    begin
      if AEncoding = nil then
        AEncoding := TEncoding.UTF8;
     
      VFileStream := TFileStream.Create(AFileName, fmCreate) ;
      try
        VPreamble := AEncoding.GetPreamble();
        VFileStream.Write(VPreamble[0], Length(VPreamble));
     
        VMemStream := TStringStream.Create(AContent, AEncoding);
        try
          VFileStream.Write(VMemStream.Bytes[0], VMemStream.Size);
        finally
          VMemStream.Free();
        end;
      finally
        VFileStream.Free();
      end;
    end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2012
    Messages
    97
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2012
    Messages : 97
    Points : 59
    Points
    59
    Par défaut
    Désolé de ne pas avoir répondu avant maintenant,
    ShaiLeTroll,
    merci pour votre réponse bien détaillée,
    même si j'ai pas pu comprendre tout le code là-dedans lol,
    en revanche, je suis tombé sur une méthode beaucoup plus simple,
    en utilisant le composant Tstringlist et sa fonction Addstrings qui permet d'insérer des lignes à partir d'autres Tstringlist:
    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
    procedure TForm1.Button1Click(Sender: TObject);
    var
    s1, s2 : tstringlist;
    begin
    s1 := TStringList.Create;
    s2 := TStringList.Create;
    s1.LoadFromFile(opendialog1.filename);
    s2.LoadFromFile(opendialog2.filename);
    with s1 do
        begin
        AddStrings(s2);
        SaveToFile(copy(opendialog1.filename,1,length(opendialog1.filename)-4)+' new.txt');
        end;
    s1.free;
    s2.free;
    end;
    Je travaille sur des fichier qui contiennent des centaines de milliers de lignes (exemple: 370,367 lignes),
    ça fonctionne parfaitement;
    par contre, avec des fichiers un peu plus grands (451,713 lignes) j'obtiens le message d'erreur:
    "Mémoire insuffisante" comme quoi le Tstringlist n'arrive pas à contenir le fichier texte,
    alors qu'il est sensé le faire, d'après Embarcadero.
    Question:

    What are the size limitations of a TStringList?

    Answer:

    TStringList can hold up to 134,217,728 strings (MaxListSize+1). There are no limits on the size of the string (other than physical memory limits and processor address space limits).
    ils disent qu'un Tstringlist peut contenir jusqu'à 134,217,728 string,
    et que la taille d'un string n'est limitée que par les capacités du CPU et de la RAM;

    est ce que vous avez une idée sur ce qui se passe là ?

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 447
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    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 447
    Points : 24 849
    Points
    24 849
    Par défaut
    C'est maximum 1 million de Char (2Go en Unicode)
    Pour les gros fichiers, j'utilise une toute autre technique avec bufferisation
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2012
    Messages
    97
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2012
    Messages : 97
    Points : 59
    Points
    59
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    C'est maximum 1 million de Char (2Go en Unicode)
    Pour les gros fichiers, j'utilise une toute autre technique avec bufferisation
    Excusez-moi mais j'aimerai bien comprendre cette ambiguïté;
    Vous dites 1 million de char, alors qu'EMBARCADERO disent que c'est plus de 134 MILLIONS de strings,
    et que la taille d'un string n'est pas limitée...
    Je me pose toutes ces questions car mes fichiers ne dépasse pas les centaines de MILLIERS de lignes;
    les fichiers de 180 mb (approximativement) se charge normalement,
    mais quand j'essaye de charger un fichier qui touche mes 250mb dans le Tstringlist j'obtiens l'erreur "Mémoire insuffisante"

    Merci encore !

  6. #6
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 447
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    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 447
    Points : 24 849
    Points
    24 849
    Par défaut
    Dès qu'un fichier dépasse 64Mo, je ne le traite plus en lecture mono-bloc

    Vous poursuivez sur une méthode plus "simple" mais qui ne fonctionne pas alors que prendre un peu de temps pour une version bufférisé, vous auriez déjà résolu le problème surtout lorsque l'on soit que le CopyStream entre deux TFileStream gère le buffer nativement soit un code extrêmement simple que je viens de pondre à l'arrache sur le forum à partir du votre

    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
    procedure TForm1.Button1Click(Sender: TObject);
    var
    s1, s2 : TFileStream;
    begin
      s1 := TFileStream.Create(opendialog1.filename, fmOpenReadWrite or fmShareExclusive);
      try
        s2 := TFileStream.Create(opendialog2.filename, fmOpenRead);
        try 
          s1.Seek(0, soEnd); // va à la fin du fichier
          s1.CopyFrom(s2, 0); // cela cache une boucle qui bufferise la copie
        finally
          s2.free;
        end;
      finally
        s1.free;
      end;
    end;
    Votre programme est en quelle version de Delphi ?
    Ansi ou Unicode, rien que cela double la consommation mémoire
    32Bits ou 64Bits,
    le 32 est limité à 2Go théorique, en pratique, difficile de monter à plus de 1950,
    le 64, monter à 8Go fonctionne
    Mais une chaine Delphi, restera limitée par sa longueur en Integer soit 2milliard de Char, je n'ai pas testé mais en 64bits c'est donc potentiellement 4Go
    le nombre de chaine n'est pas un hasard non plus 134,217,728 , on a déjà parlé de ce chiffre

    Vous avez un fichier de 250mb, passé en unicode en mémoire c'est 500Mo,
    vous le clonez alors vous avez une charge de 1Go et ce n'est que les données.
    chaque chaque chaine coute 14 octets de plus en mémoire soit 6Mo pour les entêtes et zéros terminaux

    Si vos deux fichiers font 250Mb, cela fait 500Mo + 500Mo + 500Mo cela commence à faire bcp pour un processus 32bits
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  7. #7
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2012
    Messages
    97
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2012
    Messages : 97
    Points : 59
    Points
    59
    Par défaut
    je travaille sous windows 10 64 bits
    et Delphi 10.3.3
    d'accord, je vais opter pour votre solution, l'utilisation des TfileStream
    sauf que je viens de constater que ces derniers ne possèdent pas une fonction
    SaveToFile(), comment faire pour sauvegarder le fichier fusionné? Merci

  8. #8
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 447
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    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 447
    Points : 24 849
    Points
    24 849
    Par défaut
    Vous devriez mieux étudier la classe TFileStream
    il n'y a ni LoadFromFile ni SaveToFile, vous utilisez le fichier en direct comme les fonctions E/S standard type AssignFile, ReadBlock, FileRead ...

    Essayer le code ci-dessus, il devrait fonctionner (même si je l'ai écrit sur le forum sans le tester car c'est loin d'être mon premier du genre)
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  9. #9
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2012
    Messages
    97
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2012
    Messages : 97
    Points : 59
    Points
    59
    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
    procedure TForm1.Button1Click(Sender: TObject);
    var
    s1, s2 : TFileStream;
    begin
      s1 := TFileStream.Create(opendialog1.filename, fmOpenReadWrite or fmShareExclusive);
      try
        s2 := TFileStream.Create(opendialog2.filename, fmOpenRead);
        try 
          s1.Seek(0, soEnd); // va à la fin du fichier
          s1.CopyFrom(s2, 0); // cela cache une boucle qui bufferise la copie
        finally
          s2.free;
        end;
      finally
        s1.free;
      end;
    end;
    ça marche sans faute, et c'est remarquablement plus rapide.
    Merci infiniment pour votre temps et vos réponses

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

Discussions similaires

  1. [Débutant] Ajouter une chaîne de caractère avant une autre chaîne connue dans un fichier texte en C#
    Par samuel44 dans le forum Développement Windows
    Réponses: 6
    Dernier message: 10/10/2016, 19h33
  2. Réponses: 2
    Dernier message: 17/02/2016, 14h31
  3. ajouter [une chaîne de caractères ] tableau char
    Par silver4 dans le forum Débuter
    Réponses: 8
    Dernier message: 08/03/2013, 10h21
  4. utilisation de SED pour ajouter une chaine de caractère en début de texte
    Par arnaudperfect dans le forum Shell et commandes GNU
    Réponses: 1
    Dernier message: 11/03/2008, 09h12
  5. Réponses: 4
    Dernier message: 24/07/2006, 17h34

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