2011-02-04 14 views
53

Estoy escribiendo un descargador ftp simple. Parte de que el código es algo como esto:salida a la misma línea que sobrescribe la salida anterior? python (2.5)

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

que llamo proceso de función para gestionar la devolución de llamada:

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

y la salida es algo como esto:

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

pero Quiero que imprima esta línea y la próxima vez la vuelva a imprimir/actualizar para que solo se muestre una vez y veré el progreso de esa descarga ...

¿Cómo se puede hacer?

Respuesta

95

Aquí está el código para Python 3.x:

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

La palabra clave end= es lo que hace el trabajo aquí - por defecto, print() termina en una carácter de nueva línea (\n), pero esto se puede reemplazar con una cadena diferente. En este caso, al finalizar la línea con un retorno de carro, el cursor vuelve al inicio de la línea actual. Por lo tanto, no es necesario importar el módulo sys para este tipo de uso simple. print() en realidad tiene a number of keyword arguments que se puede utilizar para simplificar enormemente el código.

Para utilizar el mismo código en Python 2.6+, ponga la siguiente línea en la parte superior del archivo:

from __future__ import print_function 
+6

Tenga en cuenta que la función de impresión también se puede usar en python 2.6+ agregando la siguiente importación en la parte superior del archivo: 'from __future__ import print_function'. – janin

+11

en python <3.0 una coma al final de la instrucción evitará un "\ n": 'print" foo ",' Sin embargo, usted todavía necesita enjuagar después de eso para ver el cambio: 'sys.stdout.flush() ' –

+9

Encontré que necesitaba incluir el' \ r' al comienzo de la cadena, y establecer 'end = ''' en su lugar para que esto funcione. No creo que a mi terminal le guste cuando termino con '\ r' – Jezzamon

14

Eche un vistazo a curses module documentation y curses module HOWTO.

ejemplo muy básico:

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

desafortunadamente, las maldiciones solo están disponibles en Unix.el OP no nos dijo a qué sistema operativo apunta su aplicación ... –

+2

Lo necesito para Windows – Kristian

+0

Estoy tan acostumbrado a trabajar con Linux que ni siquiera noté la advertencia de que el módulo es solo para UNIX en el documentos del módulo ... Gracias por señalar eso, @Adrien. –

32

Si todo lo que quiero hacer es cambiar una sola línea, utilice \r. \r significa retorno de carro. Su efecto es únicamente devolver el cursor al inicio de la línea actual. No borra nada. Del mismo modo, \b se puede utilizar para ir un personaje hacia atrás. (Algunos terminales pueden no soportar todas esas características)

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

, agregaría que '\ r' significa retorno de carro. su efecto es únicamente poner el cursor al inicio de la línea actual. no borra nada de forma similar, '\ b' se puede usar para ir un personaje hacia atrás. (algunos terminales pueden no admitir todas esas características) –

+0

'sys.stdout.write ('% s \ r', size_str ')' Creo que usted quiso decir 'sys.stdout.write ('% s \ r '% size_str)' pero no funciona – Kristian

+0

con esa corrección lo escribí OBRAS ;-), gracias – Kristian

9

Aquí es mi pequeña clase que puede volver a imprimir los bloques de texto. Borra correctamente el texto anterior para que pueda sobrescribir el texto anterior con texto nuevo más corto sin crear un desastre.

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

Esto no funcionará en Windows hasta Windows 10, porque Windows 10 es la primera ventana que admite esos caracteres de control https://en.wikipedia.org/wiki/ANSI_escape_code – user136036

5

He encontrado que para una sentencia de impresión simple en Python 2.7, sólo hay que poner una coma al final después de su '\r'.

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

Esto es más corto que otras soluciones que no son de pitón 3, pero también es más difícil de mantener.

+0

Python 2.7.10, y no imprime nada . Tal vez, puede compilarlo en línea y enviarnos un enlace para ver cómo está funcionando ...? –

3

Puede simplemente agregar '\ r' al final de la cadena más una coma al final de la función de impresión. Por ejemplo:

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

Esto es para Python 3? Si es así, ¿con el parámetro predeterminado 'end' establecido en' \ n' para que imprima '(...) KB descargado \ r \ n'. ¿Me equivoco? –

Cuestiones relacionadas