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

Python Discussion :

Progress bar lors de la copie d'un fichier


Sujet :

Python

  1. #1
    Membre averti Avatar de nekcorp
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2006
    Messages
    592
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2006
    Messages : 592
    Points : 383
    Points
    383
    Par défaut Progress bar lors de la copie d'un fichier
    Bonjour à tous,

    Je souhaite intégrer au code ci dessous une barre de progression me permettant de savoir l'état d'avancement de mes copies de fichiers.

    Voici le code :

    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
     
    # -*- coding: cp1252 -*-
    import os
    import shutil
     
    root_src_dir = 'F:\PATH_SOURCE'
    root_dst_dir = 'D:\PATH_DESTINATION'
     
    for src_dir, dirs, files in os.walk(root_src_dir):
        dst_dir = src_dir.replace(root_src_dir, root_dst_dir)
     
        if not os.path.exists(dst_dir):
            os.mkdir(dst_dir)
     
        for file_ in files:
            src_file = os.path.join(src_dir, file_)
            dst_file = os.path.join(dst_dir, file_)
     
            if os.path.exists(dst_file):
                os.remove(dst_file)
     
            shutil.copyfile(src_file, dst_file)
            print 'Le fichier %s à bien été copié !' %(file_)
    J'ai déjà inséré une barre de progression mais lors d'un transfert FTP via ce code et l'aide précieuse de ce forum :

    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
     
    # -*- coding: utf-8 -*-
     
    import os
    import ftplib
    import sys
    import time
     
    class FtpUploadTracker: 
        def __init__(self, totalSize):
            self.totalSize = totalSize
            self.sizeWritten = 0
            self.RefValue=0
            self.i=0
            self.p=0
            self.fin=''
            #print '[',
     
        def handle(self, block):
            self.sizeWritten += len(block)
            if self.sizeWritten < self.totalSize:
                if round((float(self.sizeWritten)/float(self.totalSize))*100) - self.RefValue==1:
                    i=self.i
                    if round((float(self.sizeWritten)/float(self.totalSize))*100)==100:
                        fin = "Upload terminé !"
     
                    self.p=int((float(self.sizeWritten)/float(self.totalSize))*100)
                    ligne = '[' + '#'*i + ' '*(20-i) + '] %d%% %s' % (self.p, self.fin) 
                    sys.stdout.write('\r%s' % ligne)
                    sys.stdout.flush()
                    self.i += 1
                    toto.write(str(i))
                    self.RefValue=self.RefValue+5
     
            else:
                sys.stdout.write('\r\n')
                sys.stdout.flush() 
     
     # Connect
    ftp = ftplib.FTP('hôte', 'login', 'pass')
     
    # file to send
    fichier = 'test.zip'
    print 'File Name: '+fichier
    totalSize = os.path.getsize(fichier)
    print 'Size of file: '+str(totalSize/(1024*1024))+'Mo'
    f = open(fichier, 'rb')
     
    """
    Class FtpUploadTracker
    """
    uploadTracker = FtpUploadTracker(totalSize)
     
    # Send the file
    ftp.storbinary('STOR ' + fichier, f, 1024, uploadTracker.handle)
     
    # Close file and FTP
    f.close()
    ftp.quit()
    Dans ce code lorsque j'envoyais mon fichier sur le FTP je faisais appel à ma classe FtpUploadTracker: ftp.storbinary('STOR ' + fichier, f, 1024, uploadTracker.handle). Je pouvais récupérer via block la valeur des données envoyées et donc savoir ou j'en étais dans mon upload.

    Je souhaite savoir s'il est possible de faire la même chose mais avec shutil.copyfile ?

    Merci d'avance pour votre aide.

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,

    Citation Envoyé par nekcorp Voir le message
    Je souhaite savoir s'il est possible de faire la même chose mais avec shutil.copyfile ?
    Il y a deux choses à compter: le nombre de fichiers et le nombre d'octets à recopier.
    shutil.copyfile ne pourrait vous donnez que la progression sur le nombre d'octets puis qu'il travaille "par fichier".
    Mais, il ne le fait pas.

    Ceci dit, vous pourriez "améliorer" son code pour que appeler un callback tous les XXX bytes.
    Voir les sources du module shutil.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre averti Avatar de nekcorp
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2006
    Messages
    592
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2006
    Messages : 592
    Points : 383
    Points
    383
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Salut,



    Il y a deux choses à compter: le nombre de fichiers et le nombre d'octets à recopier.
    shutil.copyfile ne pourrait vous donnez que la progression sur le nombre d'octets puis qu'il travaille "par fichier".
    Mais, il ne le fait pas.

    Ceci dit, vous pourriez "améliorer" son code pour que appeler un callback tous les XXX bytes.
    Voir les sources du module shutil.

    - W
    Si j'ai bien compris je ne pourrais effectuer un progression que sur le nombre de fichiers et non pas sur le nombre d'octets transmit par fichiers ?

    L'appel d'un callback est possible avec ftp.storbinary(). Peut être m'inspirer de ce qui a été fait avec ftplib ?

    Mais j'avouerai que je suis pas un expert, on va dire je suis un initié au langage python et j'aime vraiment ce code . Je vais avoir besoin de votre aide j'imagine

    encore merci

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Citation Envoyé par nekcorp Voir le message
    Si j'ai bien compris je ne pourrais effectuer un progression que sur le nombre de fichiers et non pas sur le nombre d'octets transmit par fichiers ?
    Lorsqu'on programme on fait ce qu'on veut (ou ce qu'on peut).
    Par contre, avant de coder, il vous faut bien choisir quoi compter: la progression sur le nombre de fichiers et/ou progression sur le nombre de blocks (total) et/ou progression sur le ou les fichiers en cours de copie.

    Il n'est pas interdit d'avoir plusieurs barres de progression...

    C'est juste un peu plus de code à écrire.
    note: et c'est vous qui tenez le crayon.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Membre averti Avatar de nekcorp
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2006
    Messages
    592
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2006
    Messages : 592
    Points : 383
    Points
    383
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Lorsqu'on programme on fait ce qu'on veut (ou ce qu'on peut).
    Par contre, avant de coder, il vous faut bien choisir quoi compter: la progression sur le nombre de fichiers et/ou progression sur le nombre de blocks (total) et/ou progression sur le ou les fichiers en cours de copie.
    - W
    Non mais ce que je voulais dire c'est que par défaut avec shutil.copyfile(), je ne peux pas récupérer les blocks afin de faire une progression sur le nombre d'octet copiés, il faut donc que je modifie le shutil.py pour pourvoir le faire ?

    Il n'est pas interdit d'avoir plusieurs barres de progression...
    Oui je peux très bien mettre une barre de progression sur le nombre de fichiers restant à copier et une qui me dit à combien de pour-cent j'en suis sur le fichier en cours de copie.

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Citation Envoyé par nekcorp Voir le message
    Non mais ce que je voulais dire c'est que par défaut avec shutil.copyfile(), je ne peux pas récupérer les blocks afin de faire une progression sur le nombre d'octet copiés, il faut donc que je modifie le shutil.py pour pourvoir le faire ?
    Je disais juste que vous pourriez vous en inspirez pour coder votre copyfile qui accepte un callback.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Membre averti Avatar de nekcorp
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2006
    Messages
    592
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2006
    Messages : 592
    Points : 383
    Points
    383
    Par défaut
    Bon j'ai récupéré les deux fonctions qui m’intéresse (celle de ftplib et celle de shutil)

    la première storbinary: celle de ftplib et qui permet de transférer les fichiers via FTP :

    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
     
    def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
            """Store a file in binary mode.  A new port is created for you.
     
            Args:
              cmd: A STOR command.
              fp: A file-like object with a read(num_bytes) method.
              blocksize: The maximum data size to read from fp and send over
                         the connection at once.  [default: 8192]
              callback: An optional single parameter callable that is called on
                        each block of data after it is sent.  [default: None]
              rest: Passed to transfercmd().  [default: None]
     
            Returns:
              The response code.
            """
            self.voidcmd('TYPE I')
            conn = self.transfercmd(cmd, rest)
            while 1:
                buf = fp.read(blocksize)
                if not buf: break
                conn.sendall(buf)
                if callback: callback(buf)
            conn.close()
            return self.voidresp()
    La deuxième copyfile : celle de shutil à laquelle je dois insérer le blocksize et le callback :

    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
     
    def copyfile(src, dst):
        """Copy data from src to dst"""
        if _samefile(src, dst):
            raise Error("`%s` and `%s` are the same file" % (src, dst))
     
        for fn in [src, dst]:
            try:
                st = os.stat(fn)
            except OSError:
                # File most likely does not exist
                pass
            else:
                # XXX What about other special files? (sockets, devices...)
                if stat.S_ISFIFO(st.st_mode):
                    raise SpecialFileError("`%s` is a named pipe" % fn)
     
        with open(src, 'rb') as fsrc:
            with open(dst, 'wb') as fdst:
                copyfileobj(fsrc, fdst)
    y a plus quà comme on dit

  8. #8
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Il est clair que la bonne solution est d'analyser le code Python du module shutil, d'en extraire les parties utiles et d'ajouter ce qui manque, c'est-à-dire le callback pendant la copie par bloc. On apprend d'ailleurs beaucoup de chose de cette façon là. En particulier pour tenir compte du caractère multi-plateforme de Python (Windows-Linux-MacOSX).

    Voilà cependant à titre d'exemple un petit code qui peut faire le boulot dans un cas très simplifié: uniquement Windows, sans transfert des droits ni de vérification de validité des données (ex: ça plantera si les données ne sont pas valides):

    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
    # Python 2
     
    import os
     
    def copiefichier(ficsource, ficdestin, lgbuf=8192, callback=None):
        """Copie le contenu du fichier source vers le fichier destination
        """
        if os.path.isdir(ficdestin):
            # la destination étant un répertoire, on lui ajoute le nom source
            ficdestin = os.path.join(ficdestin, os.path.basename(ficsource))
     
        with open(ficsource, 'rb') as fs:
            with open(ficdestin, 'wb') as fd:
                while True:
                    buf = fs.read(lgbuf)
                    if buf == "":
                        break # plus rien à copier: on a fini
                    fd.write(buf)
                    if callback!=None:
                        callback(buf) # envoi du buffer au callback si demandé
    On voit le principe: on ouvre les 2 fichiers en binaire (l'un en lecture et l'autre en écriture) et on transfère des blocs d'octets par l'intermédiaire d'un buffer dont on peut d'ailleurs modifier la taille (8192 octets ici).

    Le callback est le nom de la fonction qui peut recevoir le contenu du buffer à chaque fois qu'il est copié. On n'est bien sûr pas obligé d'en donner un.

    Voilà un exemple de progression. on utilise une classe pour pouvoir afficher le pourcentage:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Progression(object):
     
        def __init__(self, lgtotal):
            self.lgtotal = lgtotal
            self.lgcopie = 0
     
        def __call__(self, buf):
            self.lgcopie += len(buf)
            pourc = 1.0*self.lgcopie/self.lgtotal*100
            print "%.1f %%" % (pourc)
    Et voilà comment on utilise:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    ficsource = r"E:\Python34\DLLs\sqlite3.dll"
     
    ficdestin = r"E:\Temp"
     
    # on initialise la classe Progression et on lui passe comme argument la taille totale du fichier à copier (pour avoir les % !)
    progression = Progression(os.path.getsize(ficsource)) 
     
    # et on lance la copie en citant le callback à utiliser:
    copiefichier(ficsource, ficdestin, callback=progression)
    Ce qui donne pour cet exemple:

    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
    1.6 %
    3.3 %
    4.9 %
    6.6 %
    8.2 %
    9.9 %
    11.5 %
    13.2 %
    14.8 %
    16.5 %
    18.1 %
    19.8 %
    21.4 %
    23.0 %
    24.7 %
    26.3 %
    28.0 %
    29.6 %
    31.3 %
    32.9 %
    34.6 %
    36.2 %
    37.9 %
    39.5 %
    41.2 %
    42.8 %
    44.4 %
    46.1 %
    47.7 %
    49.4 %
    51.0 %
    52.7 %
    54.3 %
    56.0 %
    57.6 %
    59.3 %
    60.9 %
    62.6 %
    64.2 %
    65.8 %
    67.5 %
    69.1 %
    70.8 %
    72.4 %
    74.1 %
    75.7 %
    77.4 %
    79.0 %
    80.7 %
    82.3 %
    84.0 %
    85.6 %
    87.2 %
    88.9 %
    90.5 %
    92.2 %
    93.8 %
    95.5 %
    97.1 %
    98.8 %
    100.0 %
    [edit] pour adapter le 1er code à Python 3, il faut remplacer la ligne < if buf == "": > par < if len(buf)==0: >
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  9. #9
    Membre actif Avatar de Kurodiam
    Inscrit en
    Décembre 2013
    Messages
    208
    Détails du profil
    Informations forums :
    Inscription : Décembre 2013
    Messages : 208
    Points : 215
    Points
    215
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Lorsqu'on programme on fait ce qu'on veut (ou ce qu'on peut).
    Par contre, avant de coder, il vous faut bien choisir quoi compter: la progression sur le nombre de fichiers et/ou progression sur le nombre de blocks (total) et/ou progression sur le ou les fichiers en cours de copie.

    Il n'est pas interdit d'avoir plusieurs barres de progression...

    C'est juste un peu plus de code à écrire.
    note: et c'est vous qui tenez le crayon.

    - W
    Euh....@wiztricks , essayez aussi d'éviter les fautes grammaticales . Désolé , je n'ai pas pu m’empêcher de vous le dire , néanmoins , votre cerveau est assez bien développé
    _""""Cats have a big heart ^^ unlike some bad people (whose will never change in their brain) """

  10. #10
    Membre averti Avatar de nekcorp
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2006
    Messages
    592
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2006
    Messages : 592
    Points : 383
    Points
    383
    Par défaut
    Citation Envoyé par tyrtamos Voir le message
    Bonjour,

    Il est clair que la bonne solution est d'analyser le code Python du module shutil, d'en extraire les parties utiles et d'ajouter ce qui manque, c'est-à-dire le callback pendant la copie par bloc. On apprend d'ailleurs beaucoup de chose de cette façon là. En particulier pour tenir compte du caractère multi-plateforme de Python (Windows-Linux-MacOSX).

    Voilà cependant à titre d'exemple un petit code qui peut faire le boulot dans un cas très simplifié: uniquement Windows, sans transfert des droits ni de vérification de validité des données (ex: ça plantera si les données ne sont pas valides):

    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
    # Python 2
     
    import os
     
    def copiefichier(ficsource, ficdestin, lgbuf=8192, callback=None):
        """Copie le contenu du fichier source vers le fichier destination
        """
        if os.path.isdir(ficdestin):
            # la destination étant un répertoire, on lui ajoute le nom source
            ficdestin = os.path.join(ficdestin, os.path.basename(ficsource))
     
        with open(ficsource, 'rb') as fs:
            with open(ficdestin, 'wb') as fd:
                while True:
                    buf = fs.read(lgbuf)
                    if buf == "":
                        break # plus rien à copier: on a fini
                    fd.write(buf)
                    if callback!=None:
                        callback(buf) # envoi du buffer au callback si demandé
    On voit le principe: on ouvre les 2 fichiers en binaire (l'un en lecture et l'autre en écriture) et on transfère des blocs d'octets par l'intermédiaire d'un buffer dont on peut d'ailleurs modifier la taille (8192 octets ici).

    Le callback est le nom de la fonction qui peut recevoir le contenu du buffer à chaque fois qu'il est copié. On n'est bien sûr pas obligé d'en donner un.

    Voilà un exemple de progression. on utilise une classe pour pouvoir afficher le pourcentage:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Progression(object):
     
        def __init__(self, lgtotal):
            self.lgtotal = lgtotal
            self.lgcopie = 0
     
        def __call__(self, buf):
            self.lgcopie += len(buf)
            pourc = 1.0*self.lgcopie/self.lgtotal*100
            print "%.1f %%" % (pourc)
    Et voilà comment on utilise:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    ficsource = r"E:\Python34\DLLs\sqlite3.dll"
     
    ficdestin = r"E:\Temp"
     
    # on initialise la classe Progression et on lui passe comme argument la taille totale du fichier à copier (pour avoir les % !)
    progression = Progression(os.path.getsize(ficsource)) 
     
    # et on lance la copie en citant le callback à utiliser:
    copiefichier(ficsource, ficdestin, callback=progression)
    Ce qui donne pour cet exemple:

    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
    1.6 %
    3.3 %
    4.9 %
    6.6 %
    8.2 %
    9.9 %
    11.5 %
    13.2 %
    14.8 %
    16.5 %
    18.1 %
    19.8 %
    21.4 %
    23.0 %
    24.7 %
    26.3 %
    28.0 %
    29.6 %
    31.3 %
    32.9 %
    34.6 %
    36.2 %
    37.9 %
    39.5 %
    41.2 %
    42.8 %
    44.4 %
    46.1 %
    47.7 %
    49.4 %
    51.0 %
    52.7 %
    54.3 %
    56.0 %
    57.6 %
    59.3 %
    60.9 %
    62.6 %
    64.2 %
    65.8 %
    67.5 %
    69.1 %
    70.8 %
    72.4 %
    74.1 %
    75.7 %
    77.4 %
    79.0 %
    80.7 %
    82.3 %
    84.0 %
    85.6 %
    87.2 %
    88.9 %
    90.5 %
    92.2 %
    93.8 %
    95.5 %
    97.1 %
    98.8 %
    100.0 %
    [edit] pour adapter le 1er code à Python 3, il faut remplacer la ligne < if buf == "": > par < if len(buf)==0: >
    Merci @tyrtamos

    J'ai voulu modifier le code qui fonctionne très bien sous Windows (c'est normal car tu l'avais dit ) pour l'utiliser sous Mac via un terminal mais j'obtient un message d'erreur.

    Ci dessous le code modifié

    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
    import os
    import sys
     
    class Progression(object):
     
        def __init__(self, lgtotal):
            self.lgtotal = lgtotal
            self.lgcopie = 0
     
        def __call__(self, buf):
            self.lgcopie += len(buf)
            pourc = 1.0*self.lgcopie/self.lgtotal*100
            """print "%.1f %%" % (pourc)"""
            sys.stdout.write(pourc)
            sys.stdout.flush()
     
    def copiefichier(ficsource, ficdestin, lgbuf=8192, callback=None):
        """Copie le contenu du fichier source vers le fichier destination
        """
        if os.path.isdir(ficdestin):
            ficdestin = os.path.join(ficdestin, os.path.basename(ficsource))
     
        with open(ficsource, 'rb') as fs:
            with open(ficdestin, 'wb') as fd:
                while True:
                    buf = fs.read(lgbuf)
                    if buf == "":
                        break
                    fd.write(buf)
                    if callback!=None:
                        callback(buf)
     
     
     
    ficsource='/Volumes/DD500GO/PATH_SOURCE/PATH_SOURCE.7z'					
    ficdestin ='/Users/Desktop'
    progression = Progression(os.path.getsize(ficsource))
    copiefichier(ficsource, ficdestin, 8192, callback=progression)
    et là l'erreur renvoyé :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    Traceback (most recent call last):
      File "CopyFile_2.0.py", line 38, in <module>
        copiefichier(ficsource, ficdestin, 8192, callback=progression)
      File "CopyFile_2.0.py", line 31, in copiefichier
        callback(buf)
      File "CopyFile_2.0.py", line 14, in __call__
        sys.stdout.write(pourc)
    TypeError: expected a character buffer object
    Je ne comprend pas l'erreur renvoyé.

    J'ai simplement ajouté ces deux lignes afin d'avoir le changement d'état d'avance sur une seule ligne

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    sys.stdout.write(pourc)
    sys.stdout.flush()
    Une idée ?

    Merci d'avance

  11. #11
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    C'est normal: sys.stdout.write attend une chaine de caractères, alors que pourc est un nombre flottant: sys.stdout.write n'est pas aussi accommodant que print!

    Voilà ce que je te propose pour écrire dans une console une ligne de progression:

    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
    class Progression(object):
     
        def __init__(self, lgtotal):
            self.lgtotal = lgtotal
            self.lgcopie = 0
     
        def __call__(self, buf):
            self.lgcopie += len(buf)
            pourc = 1.0 * self.lgcopie / self.lgtotal * 100
     
            # barre avec 20 étoiles pour 100%
            nbetoiles = int(pourc / 5)
            nbespaces = 20 - nbetoiles
            sys.stdout.write("*"*nbetoiles + " "*nbespaces + " %5.1f %%" % (pourc,) + "\r")
            sys.stdout.flush()
     
            time.sleep(0.1)  # pour mise au point uniquement
    Ça donnera un truc comme (de 0% à 100%. Il y aura 20 étoiles pour 100%):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ****************      80.7 %
    Dans ce code, le "\r" (=retour chariot) est là pour revenir en début de ligne sans passer à la ligne suivante.

    J'ai ajouté time.sleep(0.1) pour qu'on ait le temps de voir l'affichage. Il faut, bien sûr, importer time, et effacer ensuite quand on a fini la mise au point.

    Ok?
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  12. #12
    Membre averti Avatar de nekcorp
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2006
    Messages
    592
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2006
    Messages : 592
    Points : 383
    Points
    383
    Par défaut
    Citation Envoyé par tyrtamos Voir le message
    Bonjour,

    C'est normal: sys.stdout.write attend une chaine de caractères, alors que pourc est un nombre flottant: sys.stdout.write n'est pas aussi accommodant que print!

    Voilà ce que je te propose pour écrire dans une console une ligne de progression:

    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
    class Progression(object):
     
        def __init__(self, lgtotal):
            self.lgtotal = lgtotal
            self.lgcopie = 0
     
        def __call__(self, buf):
            self.lgcopie += len(buf)
            pourc = 1.0 * self.lgcopie / self.lgtotal * 100
     
            # barre avec 20 étoiles pour 100%
            nbetoiles = int(pourc / 5)
            nbespaces = 20 - nbetoiles
            sys.stdout.write("*"*nbetoiles + " "*nbespaces + " %5.1f %%" % (pourc,) + "\r")
            sys.stdout.flush()
     
            time.sleep(0.1)  # pour mise au point uniquement
    Ça donnera un truc comme (de 0% à 100%. Il y aura 20 étoiles pour 100%):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ****************      80.7 %
    Dans ce code, le "\r" (=retour chariot) est là pour revenir en début de ligne sans passer à la ligne suivante.

    J'ai ajouté time.sleep(0.1) pour qu'on ait le temps de voir l'affichage. Il faut, bien sûr, importer time, et effacer ensuite quand on a fini la mise au point.

    Ok?
    Merci tyrtamos

    Effectivement dans mon exemple avec le FTP j'avais bien renseigné une chaine de caractère dans mon sys.stdout.write(). J'ai pas encore l'habitude et les automatisme mais ça va venir

    Par contre je trouve le temps de la copie très longue. J'ai testé sur un fichier de quelques Mo et la copie se fait en quelques seconde. Par contre avec le code, il met plusieurs minutes. A quoi cela est dû ?

    De plus à la fin de la copie je ne peux pas reprendre la main je reste bloqué sur cette ligne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ******************** 100%
    Je suis obligé de faire un ctrl + C et j'obtient ce message :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    ^CTraceback (most recent call last):
      File "CopyFile_2.0.py", line 42, in <module>
        copiefichier(ficsource, ficdestin, 8192, callback=progression)
      File "CopyFile_2.0.py", line 35, in copiefichier
        callback(buf)
      File "CopyFile_2.0.py", line 19, in __call__
        time.sleep(0.1)
    KeyboardInterrupt
    Merci d'avance pour votre aide.

  13. #13
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par nekcorp Voir le message
    Par contre je trouve le temps de la copie très longue. J'ai testé sur un fichier de quelques Mo et la copie se fait en quelques seconde. Par contre avec le code, il met plusieurs minutes. A quoi cela est dû ?
    Je suppose que tu n'as pas supprimé le time.sleep comme je l'ai dit? Chez moi, la copie est aussi rapide que par les autres méthodes.

    Citation Envoyé par nekcorp Voir le message
    De plus à la fin de la copie je ne peux pas reprendre la main je reste bloqué sur cette ligne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ******************** 100%
    Je te propose un autre code plus simple: le callback devient une fonction au lieu d'être une classe. On ne passe plus le buffer au callback, mais les 2 nombres entiers: nb d'octets copiés et nombre total d'octets à copier (=taille du fichier source).

    J'ai aussi ajouté ce qui manquait: lorsqu'on est à 100%, on passe à la ligne suivante.

    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
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    # Python 2
     
    import sys
    import os
     
    #############################################################################
    def progression(lgcop, lgtot):
        """barre de progression en console
        """
        # calcul du pourcentage de progression
        pourc = 1.0 * lgcop / lgtot * 100
        # barre avec 20 caractères pour 100%
        nbetoiles = int(pourc / 5) # le 5: 100% divisé par 20 étoiles
        nbespaces = 20 - nbetoiles
        sys.stdout.write("*"*nbetoiles + " "*nbespaces + " %5.1f %%" % (pourc,) + "\r")
        sys.stdout.flush()
        # après la ligne à 100%, on passe à la ligne suivante
        if lgcop==lgtot:
            sys.stdout.write("\n") 
            sys.stdout.flush()
     
    #############################################################################
    def copiefichier(ficsource, ficdestin, lgbuf=8192, callback=None):
        """Copie le contenu du fichier source vers le fichier destination
        """
        lgcop = 0  # portera le nb d'octets copiés pendant la copie
        lgtot = os.path.getsize(ficsource)  # nb total d'octets à copier
     
        if os.path.isdir(ficdestin):
            # la destination étant un répertoire, on lui ajoute le nom source
            ficdestin = os.path.join(ficdestin, os.path.basename(ficsource))
     
        with open(ficsource, 'rb') as fs:
            with open(ficdestin, 'wb') as fd:
                while True:
                    buf = fs.read(lgbuf)
                    if len(buf) == 0:
                        break  # plus rien à copier: on a fini
                    fd.write(buf)
                    if callback != None:
                        lgcop += len(buf)
                        callback(lgcop, lgtot)  # envoi des infos au callback si demandé
     
    #############################################################################
     
    # à modifier selon la copie à faire
    ficsource = r"E:\Python34\DLLs\sqlite3.dll"
    ficdestin = r"E:\Temp"
     
    copiefichier(ficsource, ficdestin, callback=progression)
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  14. #14
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,

    Citation Envoyé par nekcorp Voir le message
    Par contre je trouve le temps de la copie très longue. J'ai testé sur un fichier de quelques Mo et la copie se fait en quelques seconde. Par contre avec le code, il met plusieurs minutes. A quoi cela est dû ?

    De plus à la fin de la copie je ne peux pas reprendre la main je reste bloqué sur cette ligne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ******************** 100%
    Je suis obligé de faire un ctrl + C et j'obtient ce message :
    Le plus probable est que la copie ne se termine pas, i.e. que la condition de fin de la boucle de copie ne soit pas remplie.
    Et comme Tyrtamos n'a pas trouvé une façon simple pour que le code 2.7 soit identique à celui de 3.x, çà fout la grouille!
    Le pb est ici:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
                while True:
                    buf = fs.read(lgbuf)
                    if buf == "":     ## <--- * ici *
                        break # plus rien à copier: on a fini
                    fd.write(buf)
                    if callback!=None:
                        callback(buf) # envoi du buffer au callback si demandé
    Le soucis est que buf == "" fonctionne en 2.7 mais est inopérant en 3.x car unicode sera toujours différent de bytes.

    Une façon plus simple aurait été de penser à écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
                   if not buf:     ## <--- * ici *
                        break # plus rien à copier: on a fini
    Ce qui était facile puisque c'est dans les sources:

    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
    def copyfileobj(fsrc, fdst, length=16*1024):
        """copy data from file-like object fsrc to file-like object fdst"""
        while 1:
            buf = fsrc.read(length)
            if not buf:
                break
            fdst.write(buf)
     
    def copyfile(src, dst):
        """Copy data from src to dst"""
        ...
     
        with open(src, 'rb') as fsrc:
            with open(dst, 'wb') as fdst:
                copyfileobj(fsrc, fdst)
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  15. #15
    Membre averti Avatar de nekcorp
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2006
    Messages
    592
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2006
    Messages : 592
    Points : 383
    Points
    383
    Par défaut
    Citation Envoyé par tyrtamos Voir le message
    Je suppose que tu n'as pas supprimé le time.sleep comme je l'ai dit? Chez moi, la copie est aussi rapide que par les autres méthodes.



    Je te propose un autre code plus simple: le callback devient une fonction au lieu d'être une classe. On ne passe plus le buffer au callback, mais les 2 nombres entiers: nb d'octets copiés et nombre total d'octets à copier (=taille du fichier source).

    J'ai aussi ajouté ce qui manquait: lorsqu'on est à 100%, on passe à la ligne suivante.
    Merci pour ton retour tyrtamos, et désolé de répondre que maintenant.

    Si si j'avais bien effacé le time.sleep().

    En fait comme indiqué par wiztricks j'avais l'impression qu'à la fin de la copie ne se terminait pas, d'ou la non reprise de la main lorsque la barre de progression atteignait 100%. Cela c'est confirmé aussi par le fait que lorsque je voulais supprimer le fichier le système me disait que le fichier été utilisé, sauf lorsque dans le terminal je faisais un ctrl+c pour reprendre la main.

    Du coup la modification que préconise wiztricks semble résoudre le problème. J'ai testé sur plusieurs fichiers différents (taille et format différents) et ça semble fonctionné.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if not buf:     ## <--- * ici *
                        break # plus rien à copier: on a fini
    Je finalise et je reviens mettre le code fonctionnel au cas ou d'autres personnes seraient intéressées.

    Merci à vous deux

  16. #16
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Bizarre...

    D'après ton 1er code (la syntaxe du print), j'avais déduit que tu travaillais en Python 2. Or, le < if buf=="": > fonctionne très bien sous Python 2!

    Dès la fin de mon 1er message, j'avais dit que pour Python 3, il fallait < if len(buf)==0 > parce que le type de buf n'est plus str mais bytes. Mais, en fait, cette solution fonctionne aussi très bien avec Python 2. Cela devient donc ma solution préférée.

    Quand à la solution < if not buf: >, elle fonctionne très bien aussi dans les 2 cas, et il est même possible qu'elle soit un poil plus rapide. Mais je l'utilise rarement parce qu'elle nécessite de bien comprendre comment les différents types se convertissent en booléens. Dans le cas contraire, cela peut donner des résultats corrects mais inattendus:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if [False]:
       print "toujours vrai..."
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

Discussions similaires

  1. Réponses: 3
    Dernier message: 27/03/2013, 21h09
  2. Ajout d'une progress bar lors d'un rafraichissement
    Par Mimosa777 dans le forum Macros et VBA Excel
    Réponses: 20
    Dernier message: 16/04/2008, 15h01
  3. Réponses: 3
    Dernier message: 29/10/2006, 23h35
  4. I/O Error lors de la copie d'un fichier
    Par Rodrigue dans le forum Windows XP
    Réponses: 7
    Dernier message: 04/08/2006, 10h35
  5. erreur 70 lors de la copie d'un fichier
    Par aarlock dans le forum Access
    Réponses: 2
    Dernier message: 15/05/2006, 15h01

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