2

まだ言語を学んでいる Python の初心者として、ftplib の ftp クラス (Python 3.3 を実行) を使用して単純な ASCII ファイル転送 (STOR/PUT) を実行しようとして数日間苦労しました。

storbinary() メソッドを使用し、一貫して TypeError: "Type str はバッファー API をサポートしていません" を取得した後、このスレッドでの議論を発見しました。これは、Python 3 への ftplib のポートにバグがあることを意味します。

http://bugs.python.org/issue6822

次に、「rb」スイッチを使用して開いたファイル オブジェクトを使用して、storlines() の代わりに storbinary() を使用してみましたが、完全に機能するようです。私は Windows システムで作業しており、テスト/学習の目的で、Linux ホスト上の自分のサイトにアップロードしています。.zip ファイルと .txt ファイルの両方をアップロードし、FileZilla を使用してワークステーションにコピーした後、両方のファイルはそのままです。

私の日常業務では、gzip 圧縮された ASCII ファイルをメインフレームにアップロードする必要があります。適切な転送モードに切り替えるのを忘れて手動の FTP 転送を何度も台無しにしてしまったので、まったく同じコードを使用してバイナリ ファイルと ASCII ファイルの両方を転送できるのは不気味です!

このライブラリ クラスをどのように実装しているかについて、誰かコメントできますか?

ありがとう。

fileName = 'F:\\Data_Folder\\Test_File.txt'
fileParts = os.path.split(fileName)
putFile = fileParts[1]
cmd = 'STOR {}'.format(putFile)
fileObject = open(fileName, 'rb')
ftp.storbinary(cmd, fileObject)

fileName = 'F:\\Data_Folder\\Test_File.zip'
fileParts = os.path.split(fileName)
putFile = fileParts[1]
cmd = 'STOR {}'.format(putFile)
fileObject = open(fileName, 'rb')
ftp.storbinary(cmd, fileObject)

2013 年 6 月 28 日 - ここに戻って、この問題の「ループを閉じる」ようにします。open(fileName, 'rb') を ftp.storbinary() と一緒に使用すると、Windows と Linux の両方のホストをターゲットとして、バイナリと ASCII の両方のテキスト ファイルに対して正常に使用できますが、メインフレームをターゲットとして使用すると、テキスト ファイルが文字化けして、バイナリ ファイルとして表示されます。

ラッパー クラスにスイッチを追加して 'rb' 引数を使用してファイルを開き続けますが、代わりに storlines() を使用して転送を行うと、ファイルはそのまま宛先に到着します。メインフレーム側には、この動作をホストごとに変える可能性のある構成オプションがいくつかある可能性が高いと確信していますが、これについて言及することで、このスレッドに遭遇した人に、明らかに「 open(fileName, 'rb') と storbinary() の安全な組み合わせは、すべての FTP ホスト、特にメインフレーム システムで成功するとは限りません。試行錯誤によってのみ決定される可能性がありますが、ASCII データを転送するための正しいアプローチには、storlines() と一緒に open(fileName, 'rb') が必要になる場合があります。

4

2 に答える 2

2

3.3 のドキュメントには、storlines明示的に次のように記載されています。

ファイル オブジェクト ファイル(バイナリ モードで開かれている)から EOF まで行が読み込まれます…</p>

そのため、テキスト モードで開いたファイルを渡すことはできません。

FTP のテキスト (ASCII) モードは、Python のテキスト モードと同じではありません。特に、FTP テキストは ASCII (値が 127 を超える拡張コードページではなく、実際の 7 ビット ASCII) である必要があります。ただし、Python テキストには明示的に指定された文字セットがあり、Unicode として扱われます。ファイルが実際に UTF-8、Latin-1、CP-850 などの場合、テキスト モードは使用できません。

その上、Python と FTP の両方で、テキスト ファイルの行末を変更することが許可されています。場合によっては、Windows テキスト ファイルを Linux ボックスにアップロードして、Windows ではなく Unix の行末で表示させることができます (ただし、さまざまな事情によっては、実際にはそうではない場合もあります) しかし、それ以外の場合は、テキスト モードを使用したくありません。

要するに、テキスト ファイルをバイナリ モードで開き、バイナリ (画像) モードでアップロードすることは、おそらく正しいことです。


その間、コードはそのままで問題ありませんが、改善する方法を探している場合は、マイナーな変更の余地が常にあります。

まず、同じ 7 行を 2 回コピー アンド ペーストし、唯一の違いが 1 行の文字列である場合は、それを関数に分解します。

また、ファイルを閉じます。明示的な を追加するか、ステートメントfileObject.close()を使用することをお勧めします。with有効期間の短いスクリプトに 2 つのファイルしかない場合、大きな違いはありませんが、それでも良い考えです。後でこれを拡張して、2 つ以上のファイルを開くか、有効期間が長くなるようにすることもできます。

ファイルのベース名だけが必要な場合は、呼び出してからアクセスbasenameするよりも、呼び出した方が明確です。split[1]

細かいことを言えば、「レガシー」または別のスタイルを使用するラッパー コードがたくさんある場合を除き、独自のスタイルを発明するよりも、 PEP 8に固執する方がよいでしょう。

最後に、現在は同じように実装されているにもかかわらず、テキスト ファイルとバイナリ ファイルを別々に送信する可能性を残したい場合は、 and を記述upload_binary_fileupload_text_file、後者を 2 番目に呼び出すか、同じ関数への参照にします。ただし、おそらくこれは必要ありません。上で説明した理由と JF Sebastian のコメントでは、upload_text_file関数は将来の拡張のための便利なフックよりも、誤解を招く魅力的な迷惑である可能性が高くなります。

そう:

def upload_file(filename):
    put_file = os.path.basename(filename)
    cmd = 'STOR {}'.format(put_file)
    with open(filename, 'rb') as file_object:
        ftp.storbinary(cmd, file_object)

upload_file('F:\\Data_Folder\\Test_File.txt')
upload_file('F:\\Data_Folder\\Test_File.zip')
于 2013-05-08T18:26:36.440 に答える
0

あなたのコードは私には少し複雑に思えます.多くの変数を使用しています.これは私がそれを行う方法です:

fileName = 'F:\\Data_Folder\\Test_File.txt'

fileObject = open(fileName, 'rb')

ftp.storbinary('STOR ' + os.path.split(fileName)[1], fileObject)

同じことがzipファイルにも当てはまります。バイナリ モードでは、ファイルを一連の 1 と 0 として送信し、文字ASCIIとして転送するだけASCIIで、最終的にはすべて同じ方法で終了します。ASCIIまた、モードで実行できる何らかのエクスプロイトがあるため、モードを回避するように一般的にアドバイスされていると思います。

于 2013-05-08T18:33:31.357 に答える