2009-12-14 7 views
1

J'ai un petit script pour trier mes fichiers téléchargés et ça fonctionne très bien, mais je voudrais imprimer la progression d'un fichier, car quand il fait les gros, en ce moment je fais quelque chose comme:Comment faire progresser le déplacement du fichier en python?

print "moving..." 
os.renames(pathTofile, newName) 
print "done" 

Mais je voudrais être en mesure de voir quelque chose comme un (style [.....]) barre de progression ou d'un pourcentage imprimé à stdout.

Je n'ai pas besoin d'un gui de quelque sorte que ce soit, juste le moyen le plus simple/le moins efficace (:) de faire progresser l'opération).

Merci!

+0

Quelle est la taille de ces fichiers? Le déplacement d'un fichier normal devrait être terminé en moins de temps qu'il n'en faut pour dessiner une barre de progression. – pavium

+0

Un couple de cent Mo, ils sont déplacés à travers un réseau assez lent, donc cela prend un peu de temps. – Fishtopher

Répondre

1

Il n'y a aucun moyen d'obtenir une barre de progression car l'appel "renommer" qui déplace le fichier est un seul appel de système d'exploitation.

Il est à noter que l'appel "renommer" ne prend que du temps si la source et la destination sont différents volumes physiques. Si elles sont sur le même volume, le changement de nom ne prendra presque plus de temps. Si vous savez que vous copiez des données entre des volumes, vous pouvez utiliser des fonctions du module shutil telles que copyfileobj. Il n'y a pas de rappel pour la surveillance de la progression, mais vous pouvez implémenter votre propre objet semblable à un fichier source ou de destination pour suivre la progression.

8

Vous ne pourrez pas obtenir ce type d'information en utilisant os.renames. Votre meilleur pari est de remplacer cela par une opération de copie de fichier développée en interne, mais appelez stat sur le fichier à l'avance afin d'obtenir la taille complète afin que vous puissiez suivre jusqu'où vous êtes.

Quelque chose comme ceci:

source_size = os.stat(SOURCE_FILENAME).st_size 
copied = 0 
source = open(SOURCE_FILENAME, 'rb') 
target = open(TARGET_FILENAME, 'wb') 

while True: 
    chunk = source.read(32768) 
    if not chunk: 
     break 
    target.write(chunk) 
    copied += len(chunk) 
    print '\r%02d%%' % (copied * 100/source_size), 

source.close() 
target.close() 

Notez cependant que cela sera plus que probablement être nettement plus lent que os.rename.

+0

cette méthode augmenterait-elle considérablement la probabilité de copies de fichiers corrompus? – pablo

+0

Je ne sais pas très bien, mais cela signifie que vous devez être conscient qu'il peut s'arrêter à mi-chemin et être incomplet, mais alors vous n'avez aucun moyen d'être sûr de savoir comment os.rename fait son travail, donc si vous êtes attention, vous voudriez vérifier quand même. – Benno

+0

+1 pour la progression – MartinM

0

Cet exemple de méthode étend la réponse de Benno en estimant le temps restant et en supprimant la ligne de progression lorsque la copie est terminée.

def copy_large_file(src, dst): 
    ''' 
    Copy a large file showing progress. 
    ''' 
    print('copying "{}" --> "{}"'.format(src, dst)) 

    # Start the timer and get the size. 
    start = time.time() 
    size = os.stat(src).st_size 
    print('{} bytes'.format(size)) 

    # Adjust the chunk size to the input size. 
    divisor = 10000 # .1% 
    chunk_size = size/divisor 
    while chunk_size == 0 and divisor > 0: 
     divisor /= 10 
     chunk_size = size/divisor 
    print('chunk size is {}'.format(chunk_size)) 

    # Copy. 
    try: 
     with open(src, 'rb') as ifp: 
      with open(dst, 'wb') as ofp: 
       copied = 0 # bytes 
       chunk = ifp.read(chunk_size) 
       while chunk: 
        # Write and calculate how much has been written so far. 
        ofp.write(chunk) 
        copied += len(chunk) 
        per = 100. * float(copied)/float(size) 

        # Calculate the estimated time remaining. 
        elapsed = time.time() - start # elapsed so far 
        avg_time_per_byte = elapsed/float(copied) 
        remaining = size - copied 
        est = remaining * avg_time_per_byte 
        est1 = size * avg_time_per_byte 
        eststr = 'rem={:>.1f}s, tot={:>.1f}s'.format(est, est1) 

        # Write out the status. 
        sys.stdout.write('\r{:>6.1f}% {} {} --> {} '.format(per, eststr, src, dst)) 
        sys.stdout.flush() 

        # Read in the next chunk. 
        chunk = ifp.read(chunk_size) 

    except IOError as obj: 
     print('\nERROR: {}'.format(obj)) 
     sys.exit(1) 

    sys.stdout.write('\r\033[K') # clear to EOL 
    elapsed = time.time() - start 
    print('copied "{}" --> "{}" in {:>.1f}s"'.format(src, dst, elapsed)) 

Vous pouvez voir une version qui fonctionne pleinement dans l'entrée essentiel ici: https://gist.github.com/jlinoff/0f7b290dc4e1f58ad803.

Questions connexes