5


1

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

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

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

それで、初心者のために、私は「私には大丈夫に見える」コードのこの部分を思い付きました、しかし私は相対的なPythonのノブであるので、誰でもより良いアプローチを提案できますか? 明らかに、この質問を単純にするために、これは最後の、鐘と笛のことではありません。

どうもありがとう。

ftplibインポートFTPから#!python.exe

クラスxfile(file):def writelineswitheol(self、sequence):順にsの場合: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 * ")でのi:sess.retrlines(" RETR "i、xfile(i、' w ')。writelineswitheol)sess.quit()

更新:Python 3.0、プラットフォームはWindows XP下のMingWです。

z / os PDSはレコード区切り文字として行末に頼るのではなく、固定レコード構造を持っています。 ただし、z / os FTPサーバーは、テキストモードで送信しているときに、レコードの末尾を提供します。これにより、retrlines()は削除されます。

クロージングアップデート:

これが私の修正された解決策です、それは進行中の開発の基礎になるでしょう(例えば、内蔵のパスワードを削除する):

sysからftplibをインポートします。import exc_info

sess = ftplib.FTP( "undisclosed.server.com"、 "userid"、 "password")sess.sendcmd( "site sbd =(IBM-1047、ISO8859-1)")[[ASM]内のディレクトリ] ASML "、" ASMM "、" C "、" CPP "、" DLLA "、" DLLC "、" DLMC "、" GEN "、" HDR "、" MAC "]:sess.cwd(" 'ZLTALM.PREP]。 %s '"%dir)try:filelist = sess.nlst()xとしてftplib.error_permを除く:if(x.args [0] [:3]!=' 550 '):else else:try:os.mkdir (dir)を除いて:ファイルリストのhostfileを続ける:lines = [] sess.retrlines( "RETR" hostfile、lines.append)pcfile = open( "%s /%s"%(dir、hostfile)、 'w')行内の行の場合:pcfile.write(行 "\ n")pcfile.close()print( "Done:" dir)sess.quit()

JohnとVinayに感謝します

3 Answer


4


z / OSからデータセットを再帰的にダウンロードする方法を見つけようとしていたときに、この質問に出会ったところです。 私はメインフレームからebcdicファイルをダウンロードするために何年もの間単純なPythonスクリプトを使用してきました。 事実上これだけです。

デフwriteline(行):file.write(行 "\ n")

file = open(ファイル名、 "w")ftp.retrlines( "retr"ファイル名、writeline)


3


ファイルをバイナリとしてダウンロードし( `+ 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ループは、行の個々の文字を_eachの独自のline_に出力に書き込みます。 したがって、おそらく、 ` for `ループではなく、 ` self.write(sequence " \ r \ n ")`を実行する必要があります。 ただし、このユーティリティメソッドを追加するためだけに `+ file `をサブクラス化することは特に適切とは感じません。おそらく、 ` bells-and-whistles +`バージョンでは別のクラスにする必要があります。


1


あなたのwritelineswitheolメソッドは '\ n’の代わりに '\ r \ n’を追加してからテキストモードで開かれたファイルに結果を書き込みます。 どのプラットフォームで実行していても、その影響は不要な '\ r’になります。 '\ n’を追加するだけで、適切な行末が表示されます。

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

Python 3.xのftplib.FTP.retrlines()は、実際にはUnicode文字列であるstrオブジェクトを提供するはずです。そして、あなたがそれらを書く前にそれらをエンコードする必要があるでしょう。ボックス。 テストファイルには、(1)すべての可能な256バイト、(2)予想されるEBCDICコードページで有効なすべてのバイトを含める必要があります。

[いくつかの「衛生」発言]

  1. Pythonを3.0( "概念実証")から3.1にアップグレードすることを検討してください。

  2. コードの理解を容易にするために、配列インデックスとしてだけ、そして30年以上前にFORTRANから取り返しのつかない習慣を習得した場合に限り、 "i"を識別子として使用してください。

  3. これまでに発見された問題のうち2つ(各文字に行終了記号を追加する、誤った行終了記号)は、最初にテストしたときに現れたはずです。