2011-02-04 14 views
53

Sto scrivendo un semplice downloader ftp. Parte del al codice è qualcosa di simile:output sulla stessa riga sovrascrivendo l'output precedente? python (2.5)

ftp.retrbinary("RETR " + file_name, process) 

sto chiamando processo di funzione per gestire il callback:

def process(data): 
    print os.path.getsize(file_name)/1024, 'KB/', size, 'KB downloaded!' 
    file.write(data) 

e l'uscita è qualcosa di simile:

1784 KB/KB 1829 downloaded! 
1788 KB/KB 1829 downloaded! 
etc... 

ma voglio che stampi questa riga e la prossima volta ristampa/aggiorna in modo che lo mostri solo una volta e vedrò il progresso di quel download ...

Come può essere fatto?

risposta

95

Ecco il codice per Python 3.x:

print(os.path.getsize(file_name)/1024+'KB/'+size+' KB downloaded!', end='\r') 

Il end= parola chiave è quello che fa il lavoro qui - per impostazione predefinita, print() finisce in un newline (\n) carattere, ma questo può essere sostituito con una stringa diversa. In questo caso, terminare la riga con un ritorno a capo, invece, riporta il cursore all'inizio della riga corrente. Pertanto, non è necessario importare il modulo sys per questo tipo di utilizzo semplice. print() ha effettivamente a number of keyword arguments che può essere utilizzato per semplificare notevolmente il codice.

Per utilizzare lo stesso codice su Python 2.6+, inserire la seguente riga nella parte superiore del file:

from __future__ import print_function 
+6

Si noti che la funzione di stampa può essere utilizzata anche in python 2.6+ aggiungendo la seguente importazione nella parte superiore del file: 'da __future__ import print_function'. – janin

+11

in python <3.0 una virgola alla fine dell'istruzione impedirà un "\ n": 'stampa" pippo ",' Tuttavia, è necessario eseguire lo svuotamento successivo per vedere la modifica: 'sys.stdout.flush() ' –

+9

Ho trovato che dovevo includere il' \ r' all'inizio della stringa, e impostare 'end = ''' invece per farlo funzionare. Non penso che piaccia al mio terminale quando termino con '\ r' – Jezzamon

14

Dai un'occhiata allo curses module documentation e allo curses module HOWTO.

esempio davvero di base:

import time 
import curses 

stdscr = curses.initscr() 

stdscr.addstr(0, 0, "Hello") 
stdscr.refresh() 

time.sleep(1) 

stdscr.addstr(0, 0, "World! (with curses)") 
stdscr.refresh() 
+7

sfortunatamente, curses è disponibile solo su Unix.l'OP non ci ha indicato quale sistema operativo è destinato alla sua applicazione ... –

+2

Ne ho bisogno per Windows – Kristian

+0

Sono così abituato a lavorare sotto Linux che non ho nemmeno notato l'avviso che il modulo è solo per UNIX nel modulo documenti .. Grazie per averlo indicato, @Adrien. –

32

Se tutto quello che vogliamo fare è cambiare una sola riga, utilizzare \r. \r significa ritorno a capo. L'effetto è solo quello di riportare il punto di riferimento all'inizio della riga corrente. Non cancella nulla. Allo stesso modo, è possibile utilizzare \b per andare indietro di un carattere. (Alcuni terminali potrebbero non supportare tutte quelle caratteristiche)

import sys 

def process(data): 
    size_str = os.path.getsize(file_name)/1024, 'KB/', size, 'KB downloaded!' 
    sys.stdout.write('%s\r' % size_str) 
    sys.stdout.flush() 
    file.write(data) 
+1

vorrei aggiungere che '\ r' significa ritorno a capo. il suo effetto è unicamente quello di riportare il punto di riferimento all'inizio della riga corrente. non cancella nulla. allo stesso modo, '\ b' può essere usato per andare indietro di un carattere. (alcuni terminali potrebbero non supportare tutte quelle funzioni) –

+0

'sys.stdout.write ('% s \ r', size_str ')' Penso che intendessi 'sys.stdout.write ('% s \ r '% size_str)' ma non funziona. – Kristian

+0

con quella correzione l'ho scritto FUNZIONA ;-), grazie – Kristian

9

Ecco la mia piccola classe che può ristampare blocchi di testo. Cancella correttamente il testo precedente in modo da poter sovrascrivere il vecchio testo con un nuovo testo più breve senza creare confusione.

import re, sys 

class Reprinter: 
    def __init__(self): 
     self.text = '' 

    def moveup(self, lines): 
     for _ in range(lines): 
      sys.stdout.write("\x1b[A") 

    def reprint(self, text): 
     # Clear previous text by overwritig non-spaces with spaces 
     self.moveup(self.text.count("\n")) 
     sys.stdout.write(re.sub(r"[^\s]", " ", self.text)) 

     # Print new text 
     lines = min(self.text.count("\n"), text.count("\n")) 
     self.moveup(lines) 
     sys.stdout.write(text) 
     self.text = text 

reprinter = Reprinter() 

reprinter.reprint("Foobar\nBazbar") 
reprinter.reprint("Foo\nbar") 
+1

Questo non funzionerà in Windows fino a Windows 10, perché Windows 10 è la prima finestra a supportare quei caratteri di controllo https://en.wikipedia.org/wiki/ANSI_escape_code – user136036

5

ho trovato che per una semplice dichiarazione di stampa in python 2.7, basta mettere una virgola alla fine dopo la vostra '\r'.

print os.path.getsize(file_name)/1024, 'KB/', size, 'KB downloaded!\r', 

Questo è più breve di altre soluzioni non Python 3, ma anche più difficile da mantenere.

+0

Python 2.7.10 e non stampa nulla . Forse, puoi compilarlo online e inviarci un link per vedere come funziona ...? –

3

È possibile aggiungere "\ r" alla fine della stringa più una virgola al termine della funzione di stampa. Ad esempio:

print(os.path.getsize(file_name)/1024+'KB/'+size+' KB downloaded!\r'), 
+0

Questo è per python 3? In caso affermativo, con il parametro predefinito 'end' impostato su' \ n' in modo da stampare '(...) KB scaricato! \ R \ n'. Ho sbagliato? –

Problemi correlati