2009-10-20 49 views
23

Estoy tratando de leer un archivo de un servidor usando ssh de python. Estoy usando paramiko para conectarme. Puedo conectarme al servidor y ejecutar un comando como 'cat filename' y recuperar los datos del servidor, pero algunos archivos que intento leer tienen un tamaño de 1 GB o más.Lee un archivo del servidor con ssh usando python

¿Cómo puedo leer el archivo en el servidor línea por línea usando Python?

Información adicional: lo que se hace regularmente es ejecutar un comando 'cat filename' y almacenar el resultado en una variable y resolverlo. Pero dado que el archivo aquí es bastante grande, estoy buscando una forma de leer un archivo línea por línea en el servidor.

EDITAR: Puedo leer un montón de datos y dividirlos en líneas, pero el problema es que los datos recibidos en el búfer no siempre incluyen las líneas completas. por ejemplo, si el buffer tiene 300 líneas, la última línea solo puede ser la mitad de la línea en el servidor y la siguiente mitad será captada en la siguiente llamada al servidor. Quiero líneas completas

EDIT 2: ¿qué comando puedo usar para imprimir líneas en un archivo en un rango determinado. ¿Como imprimir las primeras 100 líneas, luego las siguientes 100 y así sucesivamente? De esta forma, el buffer siempre contendrá líneas completas.

+2

¿Puede usted no SFTP el archivo? –

+0

¿Estás leyendo línea por línea porque no quieres poner los datos en una variable de script de shell? ¿En qué final se establece la variable? El final local? ¿Es importante procesar una línea en el extremo cercano antes de leer la siguiente en el otro extremo? –

Respuesta

44

Paramiko'sSFTPClient clase le permite obtener un objeto de tipo fichero para leer datos de un archivo remoto de una manera Pythonic.

Asumiendo que tiene un proceso abierto SSHClient:

+5

+1, MUCHO mejor que jugar con gato (¡por todo lo que me gustan los felinos! -). –

+0

En mi caso, el contenido del archivo es un dato json en una sola línea (que quiero hacer json.load y almacenar en una variable). El tamaño de este archivo es ~ 200MB. Cuando trato de leer la línea en remote_file, nunca vuelve, simplemente está bloqueado. ¿Puede alguien ayudarme con esto? –

4

¿Qué quiere decir "línea por línea"? Hay muchos búferes de datos entre los hosts de la red, y ninguno de ellos está orientado a la línea.

Para que pueda leer un montón de datos, luego divídalos en líneas en el extremo cercano.

ssh otherhost cat somefile | python process_standard_input.py | do_process_locally 

O puede tener un proceso de leer un montón de datos en el otro extremo, romperlo, y dar formato a línea por línea y enviarlo a usted.

scp process_standard_input.py otherhost 
ssh otherhost python process_standard_input.py somefile | do_process_locally 

La única diferencia que me preocupa es de qué forma se reduce el volumen de datos en una tubería de red limitada. En su situación, puede o no ser importante.

No hay nada malo en general con el uso de cat sobre un tubo SSH para mover gigabytes de datos.

3
#!/usr/bin/env python 
import paramiko 
import select 
client = paramiko.SSHClient() 
client.load_system_host_keys() 
client.connect('yourhost.com') 
transport = client.get_transport() 
channel = transport.open_session() 
channel.exec_command("cat /path/to/your/file") 
while True: 
    rl, wl, xl = select.select([channel],[],[],0.0) 
    if len(rl) > 0: 
     # Must be stdout 
     print channel.recv(1024) 
+0

Buen ejemplo de paramiko, pero nuevamente resalta la naturaleza no orientada a la línea de este tipo de tarea. –

+0

Solo sigue leyéndolo hasta que obtengas una nueva línea u otro carácter de terminación de línea. – g33kz0r

9

Aquí está una extensión a @Matt Good's answer:

from contextlib  import closing 
from fabric.network import connect 

with closing(connect(user, host, port)) as ssh, \ 
    closing(ssh.open_sftp()) as sftp, \ 
    closing(sftp.open('remote_filename')) as file: 
    for line in file: 
     process(line) 
+0

Nunca antes había visto contextlib.closing. Entonces, ¿esto le permite convertir cualquier cosa con un método close() en algo similar al Administrador de Contexto, a pesar de que no tenga \ _ \ _ enter \ _ \ _ y \ _ \ _ exit \ _ \ _? – hughdbrown

+0

@hughbrown: Sí. Cualquier objeto con el método '.close()' funcionará. La implementación de 'closing' es trivial, consulte http://svn.python.org/view/python/trunk/Lib/contextlib.py?view=markup – jfs

+0

De hecho' con sftp.open ('nombre_archivo_remoto') como f : 'también funcionaría – taras

Cuestiones relacionadas