Partage
  • Partager sur Facebook
  • Partager sur Twitter

Copier-coller avec fstream

    17 septembre 2017 à 19:36:41

    Bonjour, j'essaie de faire une fonction qui copie un fichier d'un répertoire prédéfinis, et de le coller dans un autre répertoire également prédéfinis. J'ai parcouru quelques forums pour en savoir plus et j'ai utiliser le code de l'exemple du site cplusplus :
    int main()
    {
        std::ifstream path("C:/Users/utilisateur/Downloads/music.mp3");
        std::ofstream writer("C:/VstPlugins/m.mp3");
        if(path)
        {
            if(writer)
            {
                path.seekg(0,path.end);
                long sizee = path.tellg();
                path.seekg(0);
    
                char* buffer = new char[sizee];
    
                path.read(buffer,sizee);
                writer.write(buffer,sizee);
    
                delete[] buffer;
    
                path.close();
                writer.close();
    
            }
            else
            {
                std::cout << "Impossible d ecrire dans le fichier" << std::endl;
            }
        }
        else
        {
            std::cout << "impossible de lire le fichier "<< std::endl;
        }
    
    
        return 0;
    }

    Cependant, quand j'utilise ce code sur un fichier au format png, lorsque j'ouvre la copie, celle-ci n'est qu'un fond noir avec écrit au centre "imposible de lire ceci". Quand je l'utilise sur un fichier de type mp3, comme dans mon exemple, lorsque j'ouvre la copie , celle-ci est une version tres tres tres tres accélérée de la version d'origine (seulement 1minute pour lire une musique de 5minutes), et les 4 minutes restantes ne font aucun son.

    D'où est-ce que ca vient? Je précise que je n'ai rien trouvé de très informatif a propos des buffer, et que j'ai seulement appliqué le code.

    Je suis tombé sur une page de ce forum sur laquelle un utilisateur donnait un exemple de code avec un buffer qui ressemblait à ça "char[4*1024]", dans lequel il parlait de paquets mais le code était très complexe et je ne me suis pas risqué à utiliser celui-ci sans pouvoir en comprendre une ligne.

    • Partager sur Facebook
    • Partager sur Twitter
      17 septembre 2017 à 19:54:18

      Ouvre tes fichiers en mode binaire. Ca évitera que ça te supprime des données. (std::ios::binary)

      Attention également à la fin, tu ne lis pas forcément autant de données que la taille de ton buffer.

      -
      Edité par anolya 17 septembre 2017 à 19:58:53

      • Partager sur Facebook
      • Partager sur Twitter
        17 septembre 2017 à 19:59:56

        Merci pour ta methode je suis tomber sur un lien qui l'explique. En revanche il n'y a pas un endroit où je pourrai me renseigner sur tout ça ? Parce que j'applique l'ouverture binaire sans savoir en quoi ça consiste exactement ni si il y a d'autres modes d'ouverture
        • Partager sur Facebook
        • Partager sur Twitter
          17 septembre 2017 à 20:49:51

          L'ouverture binaire permet de ne pas altérer la lecture et l'écriture de donnée. Sur Windows, les sauts de ligne sont représentés sous la forme de \n\r alors que le c++ utilise \n pour les sauts de ligne (il y a donc transformation des sauts de ligne). Les caractères non affichables peuvent également être altérés ou ignorés. Le mode binaire permet de ne faire aucunes transformation.

          Par contre, avec ce code, les fichiers sont entièrement mis en mémoire. Si le fichier est plus grand que la place dispo, le programme ne va tout simplement pas fonctionner.

          Une simple boucle qui lit et écrit à partir d'un buffer statique est plus sûr et simple.

          std::array<char, 4096> buf;
          while (path.read(buf.data(), buf.size()) && writer.write(buf.data(), buf.size())) {
          }

          ou simplement

          writer << path.rdbuf();
          

          -
          Edité par jo_link_noir 17 septembre 2017 à 20:51:46

          • Partager sur Facebook
          • Partager sur Twitter
            17 septembre 2017 à 22:37:49

            @Anolya merci pour le lien, j'y suis allé faire un tour , il n'y en a pas tant que ça finalement.

            @jo_link_noir merci de participer à ce poste, je parlais dans mon énoncé d'un code complexe sur un sujet utilisant un buffer de ce genre char[4*1024], tu étais l'auteur de ce code^^

            tu avais également parlé d'une erreur bad_alloc lors de l'utilisation du code que j'ai link plus haut si le fichier était trop volumineux. C'est effectivement le cas avec mon code si je cible des fichier de plusieurs centaines de MO.

            Pour ta boucle, je ne comprend toujours pas le 4096 (donc le 4*1024 je suppose).

            • Partager sur Facebook
            • Partager sur Twitter
              17 septembre 2017 à 23:39:37

              > @jo_link_noir merci de participer à ce poste, je parlais dans mon énoncé d'un code complexe sur un sujet utilisant un buffer de ce genre char[4*1024], tu étais l'auteur de ce code^^

              J'ai ri :')

              Pourrais-tu mettre le lien du sujet en question ?

              > tu avais également parlé d'une erreur bad_alloc lors de l'utilisation du code que j'ai link plus haut si le fichier était trop volumineux. C'est effectivement le cas avec mon code si je cible des fichier de plusieurs centaines de MO.

              L'exception std::bad_alloc vient du new qui n'arrive pas à allouer suffisamment de mémoire. Tu dois avoir assez peu de mémoire disponible pour que le problème arrive avec seulement quelques centaines de Mo.

              > Pour ta boucle, je ne comprend toujours pas le 4096 (donc le 4*1024 je suppose).

              Pour ne pas se préoccuper de l'allocation dynamique, il faut un buffer de taille fixe. 4096 (4 kilos octets) est une taille généralement utilisée en interne par les implémentations de lecture/écriture de fichier. Mais n'importe quelle taille arbitraire fait l'affaire, le but est surtout d'avoir un buffer de taille fixe par lequel transitent les données.

              On peut aussi lire/écrire octet par octet, mais ce n'est pas très efficace. En réalité, le second code d'exemple fait une lecture caractère par caractère, mais le compilateur optimise généralement bien les codes de la SL. (Comprendre que le même code copié/collé des sources de la SL sera moins efficace.)

              Au passage, la boucle de mon code est fausse. Je suis allé un peu trop vite et ne prend pas en compte le nombre de caractère réellement lu par la fonction read.

              J'ai la flemme décrire un code juste, (surtout qu'il va ressembler au code compliqué) mais je peux te dire dans les grandes lignes comment il fonctionne:

              • on récupère le std::streambuf du fichier (.rdbuf()). http://en.cppreference.com/w/cpp/io/basic_ios/rdbuf
              • on utilise std::streambuf::sgetn(s, n) pour lire les données. Cette fonction retourne le nombre de caractère réellement lu. Le nombre peut être inférieur au nombre de caractère demandé. Il y a aussi une gestion d'erreur et de fin de fichier.
              • on utilise std::streambuf::sputn(s, n) ou std::ostream::write(s, n) pour écrire (avec 'n' la valeur retournée par sgetn). + une gestion des erreurs pour vérifier que le fichier est bien écrit.

              C'est possible de faire différemment, il me faudrait le code sous les yeux pour être sûr. En tout cas, tu peux utiliser writer << path.rdbuf(); qui fonctionne toujours, même si le code sera probablement plus lent.

              -
              Edité par jo_link_noir 17 septembre 2017 à 23:39:53

              • Partager sur Facebook
              • Partager sur Twitter
                18 septembre 2017 à 0:44:56


                Voici le lien sur lequel il y a ton code : https://openclassrooms.com/forum/sujet/copier-coller-un-fichier-avec-un-programme-en-c

                Je ne connaissais aucune des fonctions que tu as cité, j'ai l'impression que je vais passer des heures a potasser sur les flux^^

                Je ne comprends pas bien ce qu'est un buffer, c'est un endroit dans lequel on alloue la mémoire sous forme de tableau de char. Pourquoi ne pas faire directement un std::string? (si les programmeurs les plus émérites passent par là, je vous prierai de ne pas me frapper, merci d'avance :p)

                Et pour les fichiers plus gros que 4k octets, comment se fait-il que le buffer contiennent quand même assez d'espace?

                • Partager sur Facebook
                • Partager sur Twitter
                  18 septembre 2017 à 11:45:15

                  Pas portable mais bien plus performant et bien plus simple d'utilisation :

                  https://msdn.microsoft.com/fr-fr/library/windows/desktop/aa363851%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                    18 septembre 2017 à 16:21:16

                    AppzAppz a écrit:

                    Je ne comprends pas bien ce qu'est un buffer, c'est un endroit dans lequel on alloue la mémoire sous forme de tableau de char. Pourquoi ne pas faire directement un std::string? (si les programmeurs les plus émérites passent par là, je vous prierai de ne pas me frapper, merci d'avance :p)

                    Le terme char est ici trompeur. En réalité on a besoin d'un buffer d'octets, le C++ garanti que le type char est assez grand pour stocker un octet d'où le buffer de char. Quant au type std::string il n'est pas du tout adapté car il ne stocke que des caractères (même si eux aussi sont stockés sous la forme de char). Par exemple, l'octet 0x00 existe dans un buffer, mais dans une std::string il ne correspond à aucun caractère utilisable. Donc tous les 0x00 d'un fichier sont irrémédiablement perdus si on les mets dans une chaîne de caractères.

                    AppzAppz a écrit:

                    Et pour les fichiers plus gros que 4k octets, comment se fait-il que le buffer contiennent quand même assez d'espace?

                    Le buffer est utilisé ici dans une boucle, on lit le fichier morceaux par morceaux pour l'écrire au fur et à mesure dans un autre fichier. Le dernier bloc lu pourra faire moins de 4k, il sera lui aussi recopié pour sa longueur exacte lue.

                    • Partager sur Facebook
                    • Partager sur Twitter

                    En recherche d'emploi.

                      18 septembre 2017 à 18:34:27

                      La norme ne donne absolument aucune garantie qu'un char est 1 octet. Elle indique uniquement qu'1 char est de la taille du plus petit élément adressable en mémoire, à savoir 1 byte. Le fait que 1 byte est équivalent à 1 octet n'est qu'une coïncidence.

                      • Partager sur Facebook
                      • Partager sur Twitter
                        19 septembre 2017 à 17:40:18

                        Désolé pour l'absence je n'ai pas pu venir répondre hier, merci a tous d'avoir pu éclairer ma lanterne
                        • Partager sur Facebook
                        • Partager sur Twitter

                        Copier-coller avec fstream

                        × 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