Pregunta

Estoy tratando de automatizar la descarga de algunos archivos de texto desde un PDS z / OS, utilizando Python y ftplib.

Dado que los archivos de acogida son EBCDIC, no puedo simplemente uso FTP.retrbinary ().

FTP.retrlines (), cuando se utiliza con .writelines como su devolución de llamada abierto (archivo, w), no, por supuesto, proporcionar EOLs.

Así que, para empezar, se me ha ocurrido con este pedazo de código que "se ve bien para mí", pero como yo soy un novato Python relativa, puede alguien sugerir un mejor enfoque? Obviamente, para mantener esta simple pregunta, este no es el final, cosa campanas y silbatos.

Muchas gracias.

#!python.exe
from ftplib import FTP

class xfile (file):
    def writelineswitheol(self, sequence):
        for s in sequence:
            self.write(s+"\r\n")

sess = FTP("zos.server.to.be", "myid", "mypassword")
sess.sendcmd("site sbd=(IBM-1047,ISO8859-1)")
sess.cwd("'FOO.BAR.PDS'")
a = sess.nlst("RTB*")
for i in a:
    sess.retrlines("RETR "+i, xfile(i, 'w').writelineswitheol)
sess.quit()

Actualización: Python 3.0, la plataforma es MingW bajo Windows XP

.

z / OS PDS tiene una estructura de registro fija, en lugar de depender de los finales de línea como separadores de discos. Sin embargo, el servidor FTP z / OS, cuando se transmite en el modo de texto, proporciona las terminaciones de registro, que retrlines () quita.

Actualización de cierre:

Aquí está mi solución revisada, que será la base para el desarrollo en curso (la eliminación de contraseñas incorporadas, por ejemplo):

import ftplib
import os
from sys import exc_info

sess = ftplib.FTP("undisclosed.server.com", "userid", "password")
sess.sendcmd("site sbd=(IBM-1047,ISO8859-1)")
for dir in ["ASM", "ASML", "ASMM", "C", "CPP", "DLLA", "DLLC", "DLMC", "GEN", "HDR", "MAC"]:
    sess.cwd("'ZLTALM.PREP.%s'" % dir)
    try:
        filelist = sess.nlst()
    except ftplib.error_perm as x:
        if (x.args[0][:3] != '550'):
            raise
    else:
        try:
            os.mkdir(dir)
        except:
            continue
        for hostfile in filelist:
            lines = []
            sess.retrlines("RETR "+hostfile, lines.append)
            pcfile = open("%s/%s"% (dir,hostfile), 'w')
            for line in lines:
                pcfile.write(line+"\n")
            pcfile.close()
        print ("Done: " + dir)
sess.quit()

Muchas gracias a John y Vinay

¿Fue útil?

Solución

encontré con esta pregunta ya que estaba tratando de averiguar cómo descargar de forma recursiva los conjuntos de datos de z / OS. He estado usando un simple script en Python desde hace años para descargar archivos ebcdic de la computadora central. Es en efecto sólo hace esto:

def writeline(line):
    file.write(line + "\n")

file = open(filename, "w")
ftp.retrlines("retr " + filename, writeline)

Otros consejos

Usted debe ser capaz de descargar el archivo como un archivo binario (usando retrbinary) y utilizar el módulo codecs convertir de EBCDIC a cualquier salida de codificación que desea. Usted debe saber la página específica de códigos EBCDIC se utiliza en el sistema z / OS (por ejemplo CP500). Si los archivos son pequeñas, incluso se podría hacer algo como (para una conversión a UTF-8):

file = open(ebcdic_filename, "rb")
data = file.read()
converted = data.decode("cp500").encode("utf8")
file = open(utf8_filename, "wb")
file.write(converted)
file.close()

Actualización: Si es necesario utilizar retrlines para obtener las líneas y sus líneas se están volviendo en la codificación correcta, su enfoque no va a funcionar, porque la devolución de llamada se llama una vez para cada línea. Así, en la devolución de llamada, sequence será la línea, y el bucle for escribirá caracteres individuales de la línea a la salida, cada uno en su propia línea . Así que es probable que desee hacer self.write(sequence + "\r\n") más que el bucle for. Todavía doesn' se sienten especialmente justo a la subclase file sólo para añadir este método de utilidad, sin embargo - que probablemente tiene que estar en una clase diferente en su versión bells-and-whistles

.

Su método writelineswitheol agrega '\ r \ n' en lugar de '\ n' y luego escribe el resultado en un archivo abierto en modo texto. El efecto, sin importar la plataforma que está ejecutando en adelante, será un subproducto no deseado '\ r'. Sólo anexar '\ n' y obtendrá la línea apropiada final.

manejo de errores adecuada no debe ser relegado a una versión de "campanas y silbatos". Es necesario configurar su devolución de llamada para que su archivo abierto () está en un try / except y conserva una referencia al identificador de archivo de salida, su llamada es escribir en un try / except, y usted tiene un método callback_obj.close () que se utiliza cuando retrlines () devuelve a explícitamente file_handle.close () (en un try / except) - de esa manera se obtiene el control de errores, por ejemplo explict mensajes "no puede (abierto | escritura a | cerrar) el archivo X porque Y". Y a ahorrar tener que pensar cuando sus archivos van a ser cerrado de manera implícita y si se corre el riesgo de quedarse sin identificadores de archivo

ftplib.FTP.retrlines Python 3.x () le proporcionará los objetos que se encuentran en str cadenas Unicode efecto, y se necesita para codificar ellos antes de escribir - a menos que la codificación por defecto es latin1 que sería bastante inusual para una caja de Windows. Debe tener los archivos de prueba con (1) todos los posibles 256 bytes (2) todos los bytes que son válidos en la página de códigos EBCDIC esperado.

[a algunas observaciones "saneamiento"]

  1. debería actualizar su pitón de 3,0 (una "prueba de concepto" liberación) a 3.1.

  2. Para facilitar una mejor comprensión de su código, utilice "i" como un identificador sólo como un índice de secuencia y sólo si ha adquirido irremediablemente el hábito de FORTRAN 3 o más décadas atrás: -)

  3. Dos de los problemas descubiertos hasta ahora (introducción de final de línea para cada personaje, la terminación de línea equivocada) habría aparecido la primera vez que lo probó.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top