Frage

Ich bin versucht, zu automatisieren, den Download von text-Dateien von einem z/os-PDS, mit Python ftplib.

Da die host-Dateien sind EBCDIC, ich kann nicht einfach verwenden FTP.retrbinary().

FTP.retrlines(), wenn verwendet mit open(Datei,B).writelines als seine callback, nicht, natürlich, bieten EOLs.

So, für den Anfang habe ich mit diesem Stück code, das "sieht OK für mich", aber ich bin ein relativ Python noob, kann jemand vorschlagen, eine bessere Ansatz?Offensichtlich, um diese Frage einfach, dies ist nicht die endgültige, Glocken-und-Pfeifen Sache.

Vielen Dank.

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

Update:Python 3.0 ist die platform MingW unter Windows XP.

z/os PDSs haben einen festen Satzaufbau, anstatt auf Zeilenenden als Datensatz-Trennzeichen.Aber der z/os-FTP-server, wenn die übertragung im text-Modus, bietet der Datensatz Endungen, die retrlines() entfernt.

Schließen update:

Hier ist meine überarbeitete Lösung, die die basis für die laufende Weiterentwicklung (entfernen built-in-Kennwörter, zum Beispiel):

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

Mein Dank an John und Vinay

War es hilfreich?

Lösung

kam gerade über diese Frage, als ich versuchte, herauszufinden, wie rekursiv herunterladen Datensätze aus z / OS. Ich habe jetzt einen einfachen Python-Skript bereits seit Jahren mit ebcdic Dateien vom Mainframe zum Download bereit. Es effektiv nur tut dies:

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

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

Andere Tipps

Sie sollten in der Lage sein, um laden Sie die Datei als Binär (mit retrbinary) und die codecs Modul zur Konvertierung von EBCDIC nach Ausgabe-Kodierung, was Sie wollen.Sie sollten wissen, wie die EBCDIC-Codepage verwendet, die auf dem z/OS-system (z.B.cp500).Wenn die Dateien klein sind, man könnte ja etwas tun, wie (für eine Konvertierung zu 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()

Update: Wenn Sie verwenden müssen retrlines um die Linien und Ihre Zeilen wieder in die richtige Kodierung, Ihr Ansatz funktioniert nicht, da der callback wird aufgerufen, einmal für jede Zeile.So in der callback, sequence wird die Linie, und Ihre für-Schleife schreiben Sie einzelnen Zeichen in der Zeile der Ausgabe, jeder auf seine eigene Linie.So werden Sie wahrscheinlich wollen, zu tun self.write(sequence + "\r\n") eher als die for Schleife.Es noch nicht fühlen, besonders rechts Unterklasse file nur diese utility-Methode, obwohl es wahrscheinlich sein muss, die in einer anderen Klasse in Ihrer bells-and-whistles version.

Ihre writelineswitheol Methode Hängt ‚\ r \ n‘ statt ‚\ n‘, und dann schreibt das Ergebnis in eine Datei im Textmodus geöffnet. Der Effekt, egal auf welcher Plattform Sie laufen auf, wird eine unerwünschte ‚\ r‘ sein. Nur append ‚\ n‘, und Sie werden die entsprechende Zeile endet bekommen.

Die richtige Fehlerbehandlung soll nicht zu einem „Schnickschnack“ Version verbannt werden. Sie sollen Ihren Rückruf so einrichten, dass die Datei geöffnet () in einem Versuch ist / except und behält einen Verweis auf die Ausgabedatei Griff, Ihr Schreibaufruf ist in einem Try / außer, und Sie haben eine callback_obj.close () -Methode die Sie verwenden, wenn retrlines () zurückkehrt explizit file_handle.close () (in einem try / except) - auf diese Weise Sie explict Fehler bekommen Handhabung zB Meldungen „nicht (open | Schreiben in | schließen) Datei X, weil Y“. Und Sie sparen mit denken, wenn Sie Ihre Dateien werden implizit geschlossen werden und ob Sie von Datei-Handles knapp Gefahr

Python 3.x ftplib.FTP.retrlines () liefert in Objekte str, die sind in der Tat Unicode-Strings, und Sie werden sie kodieren müssen, bevor Sie sie schreiben - es sei denn, die Standard-Kodierung latin1 ist, die eher ungewöhnlich wäre für eine Windows-Box. Sie sollten Testdateien mit (1) alle möglichen 256 Bytes (2) alle Bytes, die in der erwarteten EBCDIC-Codepage gültig sind.

[a few "Hygiene", bemerkt]

  1. Sie sollten betrachten Sie Ihre Python von 3,0 (ein "proof of concept" release) ein Upgrade auf 3.1.

  2. besser erleichtern Ihren Codes zu verstehen, verwenden Sie „i“ als Kennung nur als Folgeindex und nur, wenn Sie unrettbar vor der Gewohnheit von Fortran-3 oder mehr Jahrzehnten erworben: -)

  3. Zwei der Probleme bisher entdeckt (Anfügen Zeilenabschluss, in jedes Zeichen, falscher Leitungsabschluss) zum ersten Mal gezeigt haben würden Sie es getestet.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top