Partage
  • Partager sur Facebook
  • Partager sur Twitter

fstream zappe des caractères...

zappe un octet de donnée à chaque fois.

Sujet résolu
    8 juillet 2007 à 16:37:17

    Salut à tous :p ,

    Je poste ici, car j'ai actuellement un problème avec fstream :euh: , et que je n'arrive pas à résoudre.
    Pour résumer le tout, j'ouvre un flux, de cette façon: "m_file.open(f_dir,ios::in|ios::out);", puis je cherche à en afficher le contenu, via get().

    Cependant, le problème est que à chaque get(), le curseur passe d'octet en octet (parfois moins, parfois plus) plutôt que de lire caractère après caractère :o (byte par byte). J'ai établit ce diagnostique grâce à tellg(), mais je n'ai aucune idée de la raison du problème, ni pourquoi cette valeur ne s'incrémente pas toujours de 8 o_O .

    Le seul moyen que j'ai trouvé pour empêcher ce dépassement étrange, est d'ajouter à l'ouverture du fichir le paramètre "ios::binary"; mais je ne vois as en quoi ça changerai quelque chose :lol: (de plus ça désactive l'utilisation de '\n' ou 'endl' lors de l'écriture dans le fichier :( ).

    Voici les deux méthodes que j'emploie sur mon fichier pour l'ouvrir et le lire:

    void Ini_File::OpenFile(const char* f_dir)
    {
        m_file.open(f_dir,ios::in|ios::out);//J'ouvre mon fichier
        m_dir=f_dir;//J'enregistre le répertoire du fichier.

        if(m_file)
            cout<<f_dir<<" ouvert avec succes!\n";
        else
            cout<<f_dir<<" introuvable. Veuillez verifier que ce fichier existe et/ou qu'il n'est pas dejà en cours d'utilisation.\n";
    }

    //

    string Ini_File::Display()
    {
        string content;
        char cache;

        m_file.seekg(0, ios::beg);//Je reviens au début du fichier

        while(!this->end())//J'ai fais une alternative au .eof(), qui compare la position actuelle à la taille du fichier, ce qui evite un dépassement de mémoire, ou une perte du flux.
        {
            m_file.get(cache);//Je récupère le caractère actuel
            content+=cache;//Je l'ajoute au string complet
        }
        m_file.seekg(0, ios::beg);//Je revient ensuite au début pour l'opération suivante
        return content;//Et finalement je renvoie le contenu du fichier.
    }

    bool Ini_File::end()
    {
        if(m_file.tellg()<m_size)//Je vérifie que le curseur n'a pas dépassé la taille du fichier (=m_size)
            return false;
        else
            return true;
    }
     


    J'utilise ici, un simple "get()", mais même avec un "getline", fstream me zappe les caractères :euh: ...

    Voila! Donc si l'un de vous a déjà eût ce problème, pourrait-il me dire comment il a fait pour le résoudre, ou si vous voyez une erreur dans mon code, pourriez-vous me dire où?

    Merci d'avance ;) !!
    • Partager sur Facebook
    • Partager sur Twitter
    Anonyme
      8 juillet 2007 à 16:42:35

      Salut,

      regarde dans ma signature, ya ya tuto sur les fichiers C++. Tu drvrasi y trouvé une réponse. (elle y est meme :lol: )

      Xav57
      • Partager sur Facebook
      • Partager sur Twitter
        8 juillet 2007 à 17:07:23

        Salut Xav57 :p ,

        Lol j'en étais sur que tu allais me sortir ça :-° ...
        Non plus sérieusement ^^ , j'avais bien lu ta doc (enfin je penses o_O ?): et si je ne me trompes pas :p , mon problème vient avec l'ouverture du fichier à la base :o ? Où je n'ai pas mis "ios::app" ni "ios::trunc".

        Si c'est bien là mon erreur, alors il y a ausi un problème ailleur, car en choisissant cette option (pour moi "ios:app", je perds instantanément le flux (tellg() me renvoie -1).

        Et si c'est vraiment pas ça :lol: , je ne vois pas trop ce que ça peux être :( (un petit indice? :-° ) ...

        En tout cas, merci pour ta réponse ;)
        • Partager sur Facebook
        • Partager sur Twitter
          8 juillet 2007 à 20:20:58

          comment ca te "zappe tes caracteres???
          tu essai d'ecrire en plein millieu d'un fichier???
          ou autre chose???
          • Partager sur Facebook
          • Partager sur Twitter
            8 juillet 2007 à 22:39:00

            Salut neuneutrinos ;) ,

            Non, je n'essaye pas d'écrire en plein milieu du fichier (dumoin pas au moment où survient le bug ;) ).
            En fait, à chaque appel de "get()", le curseur devrait normalement se déplacer d'un byte en avant (de caractère à caractère), hors là il se déplace de 8 en 8.

            Exemple si j'ai un fichier texte contenant: "Althar93"
            Au premier appel de "get()", il me renverra "A" (normal jusque là :) ), mais au suivant: directement "3", au lieu de chaque caractère comme il devrait.
            • Partager sur Facebook
            • Partager sur Twitter
              9 juillet 2007 à 4:26:28

              ios::app ouvre ton fichier et place son curseur à la fin du fichier... append
              • Partager sur Facebook
              • Partager sur Twitter
                9 juillet 2007 à 13:58:47

                Salut MatteX ;) ,

                Pour le coup du append, j'étais au courant, mais le problème et que je perds instantanément le flux: en gros pas moyen de me placer au début, ni d'écrire quoique ce soit à la fin...
                Comme j'ai dis, si je fais appel à tellg() juste après l'ouverture du fichier en mode ios::app, il me renvoie directemet -1 (signe qu'il y a une erreur... o_O ), et m'indique aussi (avec le test d'ouverture) que le fichier est "introuvable. Veuillez..."

                Pourtant ce fichier est bien là où il faut, puisque en avec le mode d'ouverture "ios::binary", il arrive à ouvrir le fichier, en extraire le contenu, écrire dedans, etc. La seule chose que je ne peux alors plus faire est de mettre des sauts de lignes :euh: (il me met des cubes à la place).
                • Partager sur Facebook
                • Partager sur Twitter
                  9 juillet 2007 à 15:15:07

                  si tu lis octets par octets, utilise ios::binary.
                  Si tu ne le fais pas, il va réagir pour "universaliser" le \n
                  En gros, il va sauter des caracteres, parce que
                  - sous Windows, un \n c'est 2 octets : 0x0D 0x0A
                  - sous Linux, c'est uniquement 0x0D
                  - sous Max, c'est 0x0A 0x0D

                  Il est possible qu'il y aie encore des spécifications.
                  L'ouverture en mode texte parre ces différences entre codages, mais si tu lis en binaire, tu es mort :
                  car si tu lis un 0x0D, il liras aussi l'octet suivant sous Windows.

                  un conseil, travaille en ios::binary : ça fait vraiment du bas niveau (octet par octet), sauf si tu veux lire un fichier texte pur.
                  • Partager sur Facebook
                  • Partager sur Twitter

                  Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                    9 juillet 2007 à 16:08:52

                    Salut Fvirtman ;) ,

                    Merci beaucoups pour l'info, j'y vois un peu plus clair à présent :) .

                    Cependant, je ne sais pas dans ce cas, quelle méthode d'ouverture choisir : binaire ou texte?
                    De plus, ça n'explique pas pourquoi rien qu'en lecture (alors que sur le tuto de Xav57 ça fonctionne) et ce même avec un fichier texte pur (pas en mode binaire), qu'il me zappe des caractères.
                    Le plus étrange est que comme j'ai dis plus haut, le saut de caractère n'est pas de valeur contstante o_O ; du coup certains passages sont à presque complets, alors que d'autres sont juste des lettres collées les unes derrières les autres.
                    Je me suis dis que mon fichier pouvait être corrompu :colere2: , mais le même problème survient sur 3 fichiers différents (mon fichier comme ci-dessous, un texte pur, et un autre fichier test).

                    Les fichiers que ma classe est censée lire sont des la forme:

                    [GROUPE1]
                    item1="abc"
                    item2=123
                    [GROUPE2]
                    item1=456
                    item2="Test"


                    Du coup, je pourrais theoriquement oublier la notion de sauts de ligne, étant donné que je lis caractère par caractère (mode binaire), mais je perds une autre propriété, la lisibilité (que le fichier soit aussi facilement lisible par nous même et que l'on puisse facilement le modifier à la main).
                    De même (et ça semble contre-dire ce que tu me dis là), je suis étonné qu'à l'affichage de mon texte (via un get() et en mode binaire, j'obtienne correctement les sauts de lignes).

                    A votre avis quelle est la meilleure méthode à employer (si visiblement mon problème n'est pas résolvable)? Mettre en place deux flux (binaire pour la lecture, et texte pour l'écriture?)? Dire adieu à la possibilité de modifier le fichier à la main(suppréssion des sauts de ligne)?
                    Mais la première méthode me parait bien lourde :colere2: et la seconde me plait pas des masses :euh: ...

                    Je n'avais pas autant de problème en utilisant FILE*, mais apparemment ce n'est pas du C++...
                    • Partager sur Facebook
                    • Partager sur Twitter
                      9 juillet 2007 à 16:27:31

                      Disons que si c'est pour relire le fichier : meme si c'est un fichier texte, tu peux le relire en binaire.

                      Tu lis caractere par caractere en binaire, et quand tu croises un 0x0D ou un 0x0A, tu vois que tu reviens a la ligne : aucun probleme de lisibilité si j'ose dire :)
                      Et ça ne t'empechera pas de le modifier avec un bloc note ! en ios::binary, tu controles tout, tu detectes les sauts de ligne qui sont codés pas 0x0D et/ou 0x0A.

                      FILE* a le meme genre de soucis avec "r" ou "rb" pour l'acces en lecture :)
                      • Partager sur Facebook
                      • Partager sur Twitter

                      Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                        9 juillet 2007 à 17:05:07

                        Ma classe a pour objet de modifier elle même les valeurs contenue dans le fichier (la modif à la main c'est en plus ^^ ).
                        En gros, elle ouvre le fichier, et l'utilisateur via des méthodes, peux aller aux différents groupes, puis item, et peut au choix en extraire a valeur, ou la remplacer par une nouvelle.

                        Du coup, même si le fichier est lisible par la classe et modifiable par l'utilisateur, elle ne l'est pas par la classe, et donc elle perd tout son intêret/utilité.

                        Je viens de faire quelques tests, en scindant mon fstream en deux flux, et j'ai toujours le même problème de sauts de caractères. Avec getline(), j'arrive à obtenir la plupart du contenu, mais il reste des sauts étranges de caractères (il manque la moitié gauche, si ce n'est du "n'importe quoi") o_O ...
                        ios::app me fais toujours instantanément perdre le flux, et trunc ne me sert à rien...

                        Par contre, j'ai constaté que le texte est lu correctement, tant qu'il n'y a pas à pasde sauts de ligne (même avec un texte pur). En gros le texte s'affiche correctement tant qu'il n'y a pas de sauts de ligne après lui.

                        Voila un exemple pour illustrer (exactement la même disposition):

                        Mon code ne fonctionne pas

                        Resultat:
                        Mon code ne fonctionne pas


                        Mais avec la disposition changée, étendu sur deux lignes:

                        Mon code ne fonctionne
                        pas

                        Resultat:
                        Mncd efnton
                        pas


                        Mais avec la disposition changée, étendu sur trois lignes:

                        Mon code ne
                        fonctionne
                        pas

                        Resultat:
                        M  dn
                        ocine
                        pas


                        Comme vous pouvez le voir, plus il y a de lignes, et le plus le contenu devient n'importe quoi...
                        Et j'ai même l'impression qu'à chaque fois il saute n_lignes caractères (comptez bien, vous verrez o_O )

                        Je commence à perdre patience ^^ . Je n'ai jamais eu de choses dans ce genre, d'habitude le problème était logique, hors là, c'est complètement aléatoire o_O ...
                        • Partager sur Facebook
                        • Partager sur Twitter
                        Anonyme
                          9 juillet 2007 à 18:47:41

                          ya une différence si tu ouvre juste avec ifstream et pas fstream ?
                          • Partager sur Facebook
                          • Partager sur Twitter
                            9 juillet 2007 à 19:30:01

                            J'avais oublié de le préciser avant ;) : mais non plus :( ... Que ça soit avec fstream, ou ifstream, c'est exactement la même chose :colere2: .
                            Je continue mes recherches sur le net, mais je n'arrive pas à trouver quoique ce soit qui s'approche de mon problème :euh: .

                            Edit: J'ai trouvé quelques liens sur le net, j'ai pu confirmer la raison de mon problème (cependant, je n'ai aucune idée de comment le résoudre).

                            http://www.cygwin.com/ml/cygwin/2006-06/msg00232.html
                            http://www.cygwin.com/ml/cygwin/2000-03/msg00265.html

                            Apparemment, la fonction "tellg()" est fautive, lorsque l'on est pas en mode "ios::binary", du coup elle a des résultats imprévisibles, tels que le saut de caractères, ou un renvoie d'erreur (ce qui bloque le flux) sans raison, etc...

                            A la base mon texte ne s'affichait pas en mode texte pur à cause de cela, car une fois ma fonction "end()" modifiée et remplacée par ça:

                            bool Ini_File::end()
                            {
                                if(!m_file.eof())
                                    return false;
                                else
                                {
                                    m_file.clear();
                                    return true;
                                }
                            }


                            Le contenu s'affiche correctement, sans aucun problème ;) . Cependant, ce n'est pas le seul endroit où je me sers de tellg(), ni surtout le seul endroit où j'ai besoin de connaître la position exacte du curseur.
                            De plus ma fonction modifiée, elle n'est plus du tout stable (puisqu'elle dépasse la mémoire du fichier, afin de renvoyer que l'on est à la fin).

                            Bref, je sais maintenant exactement où se situe le problème (sans avoir besoin de retourner tout mon code ^^ ), cependant de là à le résoudre :euh: ...
                            Chez vous, "tellg()" ne pose aucun problème? Je penses à Xav57 qui le cite dans son tuto, tu n'as aucun problème de ton côté avec cette fonction?

                            De plus, connaîtriez vous une alternative à ce "tellg()", quelque chose qui puisse servir à me renseigner sur la position active par rapport au fichier?
                            Je penses qu'une fois la taille du fichier identifié, je pourrais utiliser un compteur indépendant, qui s'incrémenterai avec chaque "get()", de façon à ne plus faire intervenir tellg(). Pensez-vous qu'il y ait une meilleure solution (partant déjà du principe que la mienne fonctionne ^^ )
                            • Partager sur Facebook
                            • Partager sur Twitter
                              10 juillet 2007 à 2:25:31

                              Bien compliqué tout ça

                              PS: teste les résultats de tes lectures (de là à ce qu'il faille nétoyer les bits d'état du flux parce que tu as atteint la fin).
                              • Partager sur Facebook
                              • Partager sur Twitter
                              C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                                10 juillet 2007 à 12:00:13

                                Salut lmghs :p ,

                                En effet, c'était un peu du n'importe quoi... Enfing bon, j'ai enfin réussi à régler mon problème :-° !
                                J'ai dis ADIEU à fstream (apporte plus de problème qu'autre chose ^^ ), et à la place j'ai maintenant deux flux, d'entrée (en binaire) et de sortie (en normal). De cette façon plus aucuns souçis avec tellg() , ou seekg() (oui oui, cette fonction aussi avait des blemes avec fstream, ou dumoins le mode texte pur) :p , et de plus, ça me fait une sécurité sur le flux et évite de faire n'importe quoi avec.

                                Voila, donc à présent toute ma classe fonctionne exactement comme je le voulais, allant de la lecture, à l'écriture (avec le remplaçement des données, sans que la disposition soit chamboulée lorsque je change la valeur d'un élément), de façon à ce que l'on puisse aussi facilement rajouter un élément/groupe à la main.

                                Bref un grand merci pour votre aide :) !! Vais pouvoir aller optimiser tout ça ^^ et virer tout mes "cout" de débuggage :-° ...

                                En tout cas meci encore ;)
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  10 juillet 2007 à 22:14:11

                                  D'expérience, on n'ouvre pas des flux textes en I+O. Soit on lit, soit on écrit. Si on veut remplacer, on passe par un fichier intermédiaire.

                                  C'est ce que je te disais dans l'autre fil: on ne peut pas faire des remplacements autrement que caractère par caractère. Pas de suppression, pas d'insertion. Il existe des feintes pour éviter de manipuler trop de choses.

                                  "Petit" exemple en pur remplacement:
                                  #include <iostream>
                                  #include <fstream>
                                  #include <string>
                                  #include <vector>
                                  #include <assert.h>

                                  const char* k_filename = "test_seek_stream.txt";

                                  typedef std::vector<std::fstream::off_type> positions_type;

                                  positions_type fill1st(bool verbose_ = false)
                                  {
                                      std::fstream f(k_filename, std::ios_base::in | std::ios_base::out | std::ios_base::trunc);
                                      if (!f) {
                                          throw std::runtime_error(std::string() + "Cannot open ``"+k_filename+"''!");
                                      }

                                      positions_type positions;
                                      for (int i=0; i!=10; ++i) {
                                          positions .push_back(f.tellp());
                                          f << "Ligne " << i << ": " << std::string(i, '#') << "\n";
                                          if (verbose_) {
                                              std::cout << "lig " << i << "\tpos=" << positions.back() << "\n";
                                          }
                                      }
                                      return positions;
                                  }

                                  void change_lines(positions_type const& positions_, bool verbose_ = false)
                                  {
                                      std::fstream f(k_filename, std::ios_base::in | std::ios_base::out );
                                      if (!f) {
                                          throw std::runtime_error(std::string() + "Cannot re-open ``"+k_filename+"''!");
                                      }

                                      unsigned int l;
                                      while (std::cout << "Quelle ligne à changer ?\n-> ", std::cin >> l)
                                      {
                                          if (l >= positions_.size()) { // @pre
                                              std::cout << "Numéro de ligne invalide (MAX=" << positions_.size() << std::endl;
                                              continue;
                                          }

                                          if (! f.seekg(positions_[l])) {
                                              throw std::runtime_error("Cannot go the expected read position");
                                          }
                                          std::string line;
                                          if (! std::getline(f, line)) {
                                              throw std::runtime_error("Cannot the read the ith line");
                                          }

                                          const std::string::size_type offset = line.find(": ") + 2;
                                          assert(offset != 0 && offset < line.length() && "Fichier invalide");

                                          const std::string text = line.substr(offset);

                                          std::cout << "Remplaçons ``" << text << "'' par une ligne d'au plus " << text.length() << " caractères\n";
                                          std::cout << "Veuillez saisir son nouveau contenu:\b-> ";
                                          std::string newText;
                                          std::cin >> newText;

                                          newText.resize(text.length(), ' ');
                                          std::cout << "Le nouveau texte sera: ``" << newText << "''" << std::endl;

                                          if (! f.seekp(positions_[l]+ offset)) {
                                              throw std::runtime_error("Cannot go the expected write position");
                                          }
                                          if (!(f << newText << std::flush)) {
                                              throw std::runtime_error("Cannot change contents");
                                          }
                                      }
                                  }

                                  int main (int argc, char **argv)
                                  {
                                      const bool verbose = true;
                                      try {
                                          const positions_type positions = fill1st(verbose);

                                          change_lines(positions, verbose);
                                          return EXIT_SUCCESS;
                                      } catch (std::exception const& e) {
                                          std::cerr << "Error: " << e.what() << std::endl;
                                      }
                                      return EXIT_FAILURE;
                                  }
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.

                                  fstream zappe des caractères...

                                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                  • Editeur
                                  • Markdown