下载文件Python和ftplib.FTP从z/操作系统
题
我试图自动下载的一些文本的文件从一个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代码页。
[一些"卫生"讲话]
你应该考虑提升你的蟒蛇从3.0(a"概念证明"释放)到3.1.
促进人们更好地了解这些代码,可使用"i"作为唯一的标识符作为一系列指标,只有如果你无可救药获得习惯从FORTRAN3个或更多十年前:-)
两个问题迄今发现的(追加线路终端的每个字,是错误的线的终结者)就已经表明了你第一次进行了测试。