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 :

[D11] Lecture dans un fichier txt (problème d'encodage)


Sujet :

Delphi

  1. #1
    Membre à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Togo

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2012
    Messages : 27
    Points : 13
    Points
    13
    Par défaut [D11] Lecture dans un fichier txt (problème d'encodage)
    Bonjour à tous,
    J'ai un problème de lecture dans un ficiher txt. Le fichier est encodé UTF8. Lorsque je lis le contenu du fichier et que je l'affiche, j'obtiens Boulevard des Armé au lieu d'avoir Boulevard des Armées.
    Voici mon code de lecture:

    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
     
    procedure TForm1.Button2Click(Sender: TObject);
    var
      F : Textfile;
      i, nbMax : integer;
      theText : String;
     
    begin
      AssignFile(F, OpenDialog1.FileName); 
      Reset(F); 
     
      //saut de lignes avant lecture
      for i := 1 to nbMax-1 do
        begin
           Readln(F);
        end;
     
      repeat
        Readln(F,theText);
     
        //vérifier si la ligne n'est pas vide, si oui on met fin à la lecture
        if copy(theText, 0, 20) = '' then
          begin
            EOF(F);
          end
     
          else
            //on affiche
     
            begin
              ListBox1.Items.Add(copy(theText, 243, 5));
            end;
     
      until EOF(F);
      Closefile(F);
    end;
    Que faut-il faire pour avoir l'affichage correct?
    Merci

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Vous avez déjà la réponse à votre question

    UTF8Decode
    TEncoding.UTF8.GetString(TEncoding.ANSI.GetBytes())
    ... selon la version de Delphi, la fonction proposée ne sera pas la même.

    Des composants comme TntUnicode support le type UTF8String pour l'affichage multi-charset dans une application Ansi, cela c'est pour Delphi 3 à Delphi 2007
    A partir de 2009 (ou un peu plus, je ne sais plus), Delphi est devenu UNICODE ce qui est encore plus un piège car la chaine UTF8 est codé en unicode avec les conversions implicites, conserver de l'UTF8 n'est plus une chose aisée si l'on ne fait pas attention entre String, AnsiString, UTF8String ou RawByteString
    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 à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Togo

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2012
    Messages : 27
    Points : 13
    Points
    13
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Vous avez déjà la réponse à votre question

    UTF8Decode
    TEncoding.UTF8.GetString(TEncoding.ANSI.GetBytes())
    ... selon la version de Delphi, la fonction proposée ne sera pas la même.

    Des composants comme TntUnicode support le type UTF8String pour l'affichage multi-charset dans une application Ansi, cela c'est pour Delphi 3 à Delphi 2007
    A partir de 2009 (ou un peu plus, je ne sais plus), Delphi est devenu UNICODE ce qui est encore plus un piège car la chaine UTF8 est codé en unicode avec les conversions implicites, conserver de l'UTF8 n'est plus une chose aisée si l'on ne fait pas attention entre String, AnsiString, UTF8String ou RawByteString
    j'utilise delphi 11

  4. #4
    Membre à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Togo

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2012
    Messages : 27
    Points : 13
    Points
    13
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Vous avez déjà la réponse à votre question

    UTF8Decode
    TEncoding.UTF8.GetString(TEncoding.ANSI.GetBytes())
    ... selon la version de Delphi, la fonction proposée ne sera pas la même.

    Des composants comme TntUnicode support le type UTF8String pour l'affichage multi-charset dans une application Ansi, cela c'est pour Delphi 3 à Delphi 2007
    A partir de 2009 (ou un peu plus, je ne sais plus), Delphi est devenu UNICODE ce qui est encore plus un piège car la chaine UTF8 est codé en unicode avec les conversions implicites, conserver de l'UTF8 n'est plus une chose aisée si l'on ne fait pas attention entre String, AnsiString, UTF8String ou RawByteString
    j'ai tester les conversions mais rien n'y fait
    J'ai oublié de dire, lorque je convertis le fichier en ANSI avec notepad++ ou notepad (windows) l'affichage est correct

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Si Delphi 11, oublier TextFile !
    Déjà theText en string est une erreur, il faut la déclarer en AnsiString
    Puis ensuite faire un UTF8ToString(theText);
    Les conversions implicites souvent mal comprises nuisent à ceux qui tentent maladroitement des conversions explicites.

    Passer par un TStringStream en donnant l'Encoding si vous n'avez pas de BOM
    Idem via un TStringList LoadFromFile


    Sinon, pour de gros fichiers, TFileStream, lecture en binaire et GetString(TBytes), ma méthode préférée mais cela demande certaines habitudes sur manipulation de Char (Ansi\Wide) et Byte.
    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

  6. #6
    Membre à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2012
    Messages
    27
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Togo

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2012
    Messages : 27
    Points : 13
    Points
    13
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Si Delphi 11, oublier TextFile !
    Déjà theText en string est une erreur, il faut la déclarer en AnsiString
    Puis ensuite faire un UTF8ToString(theText);
    Les conversions implicites souvent mal comprises nuisent à ceux qui tentent maladroitement des conversions explicites.

    Passer par un TStringStream en donnant l'Encoding si vous n'avez pas de BOM
    Idem via un TStringList LoadFromFile


    Sinon, pour de gros fichiers, TFileStream, lecture en binaire et GetString(TBytes), ma méthode préférée mais cela demande certaines habitudes sur manipulation de Char (Ansi\Wide) et Byte.
    j'essaie les manip mais hummmm
    est-il au moins possible de convertir le fichier même en ANSI avant la lecture en utilisant delphi?

  7. #7
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    fonction inspirée de file_get_contents en PHP

    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
     
    function file_get_contents_utf8(const AFileName: string): UTF8String;
    var
      Stream: TFileStream;
      Len: Integer;
    begin
      try
        Stream := TFileStream.Create(AfileName, fmOpenRead or fmShareDenyNone);
        try
          Len := Stream.Size;
          SetLength(Result, Len);
          Stream.ReadBuffer(Result[1], Len);
        finally
          Stream.Free;
        end;
      except
        Result := '';
      end;
    end;
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  8. #8
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    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 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Citation Envoyé par elmin Voir le message
    j'essaie les manip mais hummmm
    est-il au moins possible de convertir le fichier même en ANSI avant la lecture en utilisant delphi?
    Quel manip, vous avez plusieurs approches, fournissez votre code, là, on avance pas !

    Je ne comprends pas la question
    Si vous avez un fichier UTF8, vous pouvez le lire en Delphi mais il faut savoir ce que l'on, surtout si il n'y a pas de BOM
    Vous pouvez utiliser TEncoding si vous avez besoin d'une TStringList ensuite

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var SL := TStringList.Create();
    try
      LoadFromFile(OpenDialog1.FileName, TEncoding.UTF8); // fonction native, faut juste lire la documentation !
      for var S in SL do
        if Length(S) > 0 then
          ListBox1.Items.Add(copy(S , 243, 5));
    finally
      SL.Free();
    end;

    la fonction file_get_contents_utf8 fournie par Paul Toth est le cas évoqué par TFileStream.
    A savoir, que l'affectation d'une UTF8String dans une string devrait provoquer une conversion implicite
    Plus difficile à manipuler par la suite sauf à la repasser en TStringList mais cela aurait pu être fait plus efficacement.

    Par exemple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     ListBox1.Items.Text := file_get_contents_utf8(OpenDialog1.FileName);
    Evidemment, vous devrez faire une TStringList intermédiaire, si votre but n'est de conserver que les 243ème à 248ème caractère, attention d'ailleurs, en UTF8, il faut compenser le cas de multi-octet, le plus simple serait de laisser la conversion vers unicide se faire puis de traiter les chaines converties

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    with TStringList.Create() do
    try
      Text := file_get_contents_utf8(OpenDialog1.FileName); // UTF8String converti implicitement en UTF16.
      for var i := 0 to Count - 1 do
        if Length(Strings[I]) > 0 then
          ListBox1.Items.Add(copy(Strings[I], 243, 5));
    finally
      Free();
    end;
    ou chanceux que tu es en D11 avec le var inline qui rend le with presque obsolète (déjà il manque une sorte de WithIt pour écrire un for var S in WithIt)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var SL := TStringList.Create();
    try
      Text := file_get_contents_utf8(OpenDialog1.FileName); // UTF8String converti implicitement en UTF16.
      for var S in SL do
        if Length(S) > 0 then
          ListBox1.Items.Add(copy(S , 243, 5));
    finally
      SL.Free();
    end;
    J'ai D11.r2 depuis peu, je n'ai pas testé le code ci-dessus mais je suis impatient de pouvoir écrire ce genre de chose prochainement (pour le fun car ça coupe toute rétro-compatibilité)



    Concept différent à file_get_contents_utf8, on lit le fichier et l'on récupère une chaine décodée unicode à partir de la donnée brute ANSI, UTF8, ...

    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
    function SLTLoadFromFile(const AFileName: string; ADefaultEncoding: TEncoding = nil): string;
    var
      VFileStream: TFileStream;
      VSize: Integer;
      VPreamble: TBytes;
      VPreambleSize: Integer;
      VEncoding: TEncoding;
      VMemStream: TBytesStream;
    begin
      if not Assigned(ADefaultEncoding) then
        ADefaultEncoding := TEncoding.ANSI;
     
      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, ADefaultEncoding);
          VSize := VFileStream.Size - VPreambleSize;
        end
        else
        begin
          VEncoding := ADefaultEncoding;
          VPreambleSize := 0;
          VSize := VFileStream.Size;
        end;
     
        VFileStream.Seek(VPreambleSize, soBeginning);
     
        VMemStream := TBytesStream.Create();
        try
          VMemStream.CopyFrom(VFileStream, VSize);
          Result := VEncoding.GetString(VMemStream.Bytes);
        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

Discussions similaires

  1. Lecture dans un fichier .txt
    Par benobab dans le forum C
    Réponses: 5
    Dernier message: 05/03/2014, 23h00
  2. Réponses: 4
    Dernier message: 24/05/2010, 13h06
  3. Problème de lecture/ecriture dans un fichier txt
    Par fraid49 dans le forum Général Python
    Réponses: 6
    Dernier message: 20/11/2008, 11h32
  4. Problème de lecture dans un fichier xml
    Par Pyra dans le forum Langage
    Réponses: 2
    Dernier message: 18/12/2005, 00h13
  5. Réponses: 12
    Dernier message: 14/06/2004, 13h06

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