我试图自动下载的一些文本的文件从一个z/os PDS,使用Python和ftplib.

由于主机的文件EBCDIC,我不能简单地使用FTP.retrbinary().

FTP.retrlines(),当使用开放(文件,w)。writelines作为其回调,不,当然,提供EOLs.

因此,对于初学者来说,我已经想出了这块代码"看起来"确定"我",而是因为我是一个相对蟒蛇小白,任何人都可以建议一种更好的方法?显然,要让这个问题很简单,这并不是最终的,钟声和汽笛声的东西。

非常感谢。

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

更新:蟒蛇3.0、平台是MingW下Windows XP。

z/os Pds有固定的记录的结构,而不是依赖于行的结局作为记录的分离器。然而,z/os FTP服务器中,发射时在案文的模式,提供记录结局,其retrlines()条关闭。

关闭更新:

这是我的修订解决方案,这将依据正在进行的发展(消除内在的密码,例如):

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

我感谢这两个约翰和维奈

有帮助吗?

解决方案

碰到这个问题就来了,因为我试图找出如何从递归z / OS的下载数据集。我一直在使用一个简单的Python脚本好几年了,从主机下载EBCDIC文件。它有效地只是做这样的:

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

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

其他提示

您应该能够下载文件作为二进制(使用retrbinary),并使用codecs模块从EBCDIC转换到任何输出编码你想要的。你应该知道在z / OS系统上使用的特定EBCDIC代码页(如CP500)。如果文件很小,你甚至可以做这样的事情(为转换为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()

更新:如果您需要使用retrlines得到线和您的线条都回来在正确的编码,你的做法是行不通的,因为回调的每一行调用一次。所以在回调,sequence会就行了,你的循环将在该行的输出写入单个字符,各在自己的行的。所以,你可能想要做self.write(sequence + "\r\n")而非for循环。它仍然没有按”感觉继承file只是为了增加该实用程序方法特别合适的,虽然 - 它可能需要在你的bells-and-whistles版本不同的类

你writelineswitheol方法的附加' '代替' ',然后将结果写入到文件中开设在文本模式。效果,不论什么样的平台上运行,将是一个不必要的' '。只是添加" "你会得到适当的线路的结局。

适当的错误处理,不应沦为一个"花里胡哨"的版本。你应该设置你回调,使你的文件open()正在尝试/除外并保留了一个参考输出的文件的处理,你写信呼吁是在尝试/除外,并且你有一个callback_obj.close()方法,它使用当retrlines()返回到明确file_handle.close()(在试图/除外)--即方式你得到explict错误处理,例如消息"不能(开|写|靠近)的文件X,因为Y"和保存具有想当你的文件将含蓄地关闭,以及是否危险在运行的文件处理。

蟒蛇3.x ftplib.FTP。retrlines()应该给你str的对象,这是有效的Unicode弦,你会需要进行编码,他们之前,你写-除非默认的编码是latin1这将是相当不寻常的一窗框。你应该试验的文件(1)所有可能的256个字节(2)所有的字节,是有效的预期EBCDIC代码页。

[一些"卫生"讲话]

  1. 你应该考虑提升你的蟒蛇从3.0(a"概念证明"释放)到3.1.

  2. 促进人们更好地了解这些代码,可使用"i"作为唯一的标识符作为一系列指标,只有如果你无可救药获得习惯从FORTRAN3个或更多十年前:-)

  3. 两个问题迄今发现的(追加线路终端的每个字,是错误的线的终结者)就已经表明了你第一次进行了测试。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top