Question

Je suis en train d'automatiser le téléchargement de certains fichiers texte à partir d'un PDS z / OS, en utilisant Python et ftplib.

Étant donné que les fichiers hôtes sont EBCDIC, je ne peux pas simplement utiliser FTP.retrbinary ().

FTP.retrlines (), lorsqu'il est utilisé avec ouverte (fichier, w) .writelines que sa fonction de rappel, ne doit pas, bien sûr, de fournir EOL.

Alors, pour commencer, je suis venu avec ce morceau de code qui « me semble OK », mais comme je suis un noob Python relatif, peut-on proposer une meilleure approche? De toute évidence, de garder cette simple question, ce n'est pas la finale, chose cloches et de sifflets.

Merci.

#!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()

Mise à jour: Python 3.0, la plate-forme est MinGW sous Windows XP

.

z / OS PDS ont une structure d'enregistrement fixe, plutôt que de compter sur les fins de ligne comme séparateurs d'enregistrement. Cependant, le serveur FTP z / OS, lors de la transmission en mode texte, fournit les terminaisons de disques, qui retrlines () des bandes hors tension.

Mise à jour de clôture:

Voici ma solution révisée, qui sera la base pour le développement en cours (suppression des mots de passe intégrés, par exemple):

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()

Je tiens à remercier John et Vinay

Était-ce utile?

La solution

Juste suis tombé sur cette question alors que je tentais de comprendre comment télécharger des jeux de données récursive de z / OS. Je me sers d'un script python simple pour les années maintenant pour télécharger les fichiers ebcdic de l'ordinateur central. Efficacement fait ceci:

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

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

Autres conseils

Vous devriez pouvoir télécharger le fichier en tant que binaire (en utilisant retrbinary) et utiliser le module codecs convertir EBCDIC à tout ce que vous voulez coder la sortie. Vous devez connaître la page de code EBCDIC spécifique utilisé sur le système z / OS (par exemple CP500). Si les fichiers sont petits, vous pouvez même faire quelque chose comme (pour une conversion en 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()

Mise à jour: Si vous devez utiliser retrlines pour obtenir les lignes et vos lignes reviennent dans le codage correct, votre approche ne fonctionnera pas, car le rappel est appelé une fois pour chaque ligne. Ainsi, dans le rappel, sequence sera la ligne, et votre boucle rédigera caractères individuels dans la ligne à la sortie, chacun sur sa propre ligne . Donc, vous voulez probablement faire self.write(sequence + "\r\n") plutôt que la boucle de for. Il reste doesn se sentent surtout droit à la sous-classe file juste pour ajouter cette méthode utilitaire, bien - il a probablement besoin d'être dans une autre classe dans votre version bells-and-whistles

.

Votre méthode writelineswitheol ajoute « \ r \ n » au lieu de « \ n » et écrit ensuite le résultat à un fichier ouvert en mode texte. L'effet, peu importe la plateforme que vous utilisez, sera un indésirable « \ r ». Juste ajouter « \ n » et vous obtiendrez la ligne appropriée de fin.

manipulation d'erreur appropriée ne doit pas être reléguée à une version « cloches et de sifflets ». Vous devez configurer votre rappel afin que votre fichier ouvert () est dans un try / except et conserve une référence à la poignée de fichier de sortie, votre appel d'écriture est dans un try / except, et vous avez une méthode callback_obj.close () qui vous utilisez lorsque retrlines () retourne explicitement file_handle.close () (dans un try / except) - de cette façon vous obtenez la gestion des erreurs explict par exemple messages « ne peut pas (ouvrir | écrire | fermer) fichier X parce que Y ». ET vous éviter d'avoir à penser quand vos fichiers vont être implicitement fermé et que vous risquez de manquer de descripteurs de fichiers

3.x Python ftplib.FTP.retrlines () devrait vous donner des objets str qui sont dans les chaînes Unicode effet, et vous aurez besoin de les encoder avant de les écrire - à moins que l'encodage par défaut est latin1 qui serait plutôt inhabituel pour une boîte de Windows. Vous devriez avoir des fichiers de test avec (1) tous les 256 octets possibles (2) tous les octets qui sont valides dans la page de code EBCDIC attendu.

[quelques remarques "assainissement"]

  1. Vous devriez envisager d'améliorer votre Python de 3,0 (une « preuve de concept » libération) à 3,1.

  2. Afin de faciliter une meilleure compréhension de votre code, utilisez « i » comme identifiant seulement comme un indice de séquence et seulement si vous avez acquis incurablement l'habitude il y a de FORTRAN 3 ans ou plus: -)

  3. Deux des problèmes découverts à ce jour (annexant terminaison de ligne à chaque caractère, terminaison de ligne mal) aurait montré la première fois que vous le testiez.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top