Python および ftplib.FTP を使用した z/os からのテキスト ファイルのダウンロード

StackOverflow https://stackoverflow.com/questions/1184844

  •  19-09-2019
  •  | 
  •  

質問

Python と ftplib を使用して、z/os PDS からのテキスト ファイルのダウンロードを自動化しようとしています。

ホスト ファイルは EBCDIC であるため、単純に FTP.retrbinary() を使用することはできません。

FTP.retrlines() は、open(file,w).writelines をコールバックとして使用した場合、もちろん EOL を提供しません。

それで、手始めに、「私には大丈夫に見える」このコードを思いつきましたが、私はPythonの初心者なので、誰かがより良いアプローチを提案できますか?明らかに、この質問を簡潔にするために、これは最終的な付加機能ではありません。

どうもありがとう。

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

アップデート:Python 3.0、プラットフォームは Windows XP 上の MingW です。

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 行を取得し、行が正しいエンコーディングで返される場合、コールバックは行ごとに 1 回呼び出されるため、このアプローチは機能しません。したがって、コールバックでは、 sequence が行になり、for ループは行内の個々の文字を出力に書き込みます。 それぞれが独自の行にある. 。だからあなたはおそらくやりたいでしょう self.write(sequence + "\r\n") ではなく for ループ。サブクラス化するのが特に適切とはまだ思えません file ただし、このユーティリティ メソッドを追加するだけです - おそらく、あなたの環境の別​​のクラスにある必要があります。 bells-and-whistles バージョン。

writelineswitheol メソッドは、「 」の代わりに「 」を追加し、結果をテキスト モードで開かれたファイルに書き込みます。実行しているプラ​​ットフォームに関係なく、その影響は不要な ' ' になります。「 」を追加するだけで、適切な行末が得られます。

適切なエラー処理を「追加機能」バージョンに追いやるべきではありません。ファイル open() が Try/Except 内にあり、出力ファイル ハンドルへの参照を保持するように、書き込み呼び出しが Try/Except 内にあり、callback_obj.close() メソッドがあるようにコールバックを設定する必要があります。 retrlines() が明示的に file_handle.close() に(try/Exception で)戻るときに使用します。こうすることで、明示的なエラー処理が得られます。「Y のため、ファイル X を (開く|書き込み|閉じる) ことはできません」というメッセージが表示され、ファイルがいつ暗黙的に閉じられるか、ファイル ハンドルが不足する危険性があるかどうかを考える必要がなくなりました。

Python 3.x ftplib.FTP.retrlines() は、事実上 Unicode 文字列である str オブジェクトを提供するはずであり、デフォルトのエンコードが Windows ではかなり珍しい latin1 でない限り、それらを記述する前にエンコードする必要があります。箱。(1) 考えられるすべての 256 バイト (2) 予想される EBCDIC コードページで有効なすべてのバイトを含むテスト ファイルが必要です。

[いくつかの「衛生」に関するコメント]

  1. Python を 3.0 (「概念実証」リリース) から 3.1 にアップグレードすることを検討する必要があります。

  2. コードの理解を容易にするために、シーケンス インデックスとしてのみ、また数十年前に FORTRAN 3 から取り返しのつかない習慣を身につけた場合にのみ、識別子として「i」を使用してください :-)

  3. これまでに発見された問題のうち 2 つ (各文字に行末文字を追加する、間違った行末文字) は、最初にテストしたときに発生する可能性があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top