では、Python のftplibを使用して FTP サーバーからログ ファイルのリストを取得するとします。そのファイルのリストを解析して、リスト内のファイル名 (最後の列) だけを取得するにはどうすればよいですか? 出力例については、上記のリンクを参照してください。
7 に答える
retrlines()を使用することは、コンソールに出力するだけであり、その出力を取得するためにトリッキーなことをしなければならないため、おそらく最良のアイデアではありません。おそらくより良い方法は、nlst()メソッドを使用することです。これは、必要なもの、つまりファイル名のリストを正確に返します。
このベストアンサー
ftp.nlst()
の代わりに使用することをお勧めしますftp.retrlines()
。それはあなたが望むものを正確に与えるでしょう。
できない場合は、以下をお読みください。
sysadminプロセスのジェネレーター
彼の今では有名なレビュー、システムプログラマーのためのジェネレータートリックの紹介で、David M. Beazleyは、wuickと再利用可能なコードでこの種のデータ問題に答えるために多くのレシピを提供しています。
EG:
# empty list that will receive all the log entry
log = []
# we pass a callback function bypass the print_line that would be called by retrlines
# we do that only because we cannot use something better than retrlines
ftp.retrlines('LIST', callback=log.append)
# we use rsplit because it more efficient in our case if we have a big file
files = (line.rsplit(None, 1)[1] for line in log)
# get you file list
files_list = list(files)
すぐにリストを生成してみませんか?
これを行うと、柔軟性が大幅に向上するためです。ファイルを変換する前に、任意の中間ジェネレーターをフィルターに適用できます。files_list
パイプのように、ラインを追加し、過熱することなくプロセスを追加します(ジェネレーターであるため)。そして、あなたが取り除けばretrlines
、それでもうまくいきます。リストを一度も保存しないので、それはさらに良いことです。
編集:まあ、私は他の答えへのコメントを読みました、そしてそれは名前にスペースがあるならばこれはうまくいかないと言います。
かっこいい、これはこの方法が便利な理由を説明します。プロセスで何かを変更したい場合は、行を変更するだけです。スワップ:
files = (line.rsplit(None, 1)[1] for line in log)
と
# join split the line, get all the item from the field 8 then join them
files = (' '.join(line.split()[8:]) for line in log)
わかりました、これはここでは明らかではないかもしれませんが、巨大なバッチプロセススクリプトの場合、それは素晴らしいです:-)
ちなみに、なんらかの理由でretrlines()を使用している場合は、retrlines()の2番目の引数として関数を渡すのが少し最適ではありません。リスト内のアイテムごとに呼び出されます。したがって、次のようなもの(「ftp」という名前のFTPオブジェクトがあると仮定)も同様に機能します。
filenames = []
ftp.retrlines('LIST', lambda line: filenames.append(line.split()[-1]))
リスト'filenames'は、ファイル名のリストになります。
出力のすべてのファイル名は同じ列から始まるため、最初の行のドットの位置を取得するだけです。
drwxrwsr-x 5 ftp-usr pdmaint 1536 Mar 20 09:48 .
次に、そのドットの位置を開始インデックスとして使用して、ファイル名を他の行からスライスします。
ドットは行の最後の文字であるため、行の長さから1を引いたものをインデックスとして使用できます。したがって、最終的なコードは次のようになります。
lines = ftp.retrlines('LIST')
lines = lines.split("\n") # This should split the string into an array of lines
filename_index = len(lines[0]) - 1
files = []
for line in lines:
files.append(line[filename_index:])
ftplib.FTP.nlst()が機能しない理由はありますか?チェックしたところ、指定されたディレクトリ内のファイルの名前のみが返されます。
FTP サーバーがコマンドをサポートしている場合は、その回答MLSD
のセクション「単一ディレクトリのケース」を参照してください。
クラスのインスタンス (たとえばftpd
) を使用し、接続されたインスタンスでそのメソッドを正しいフォルダーにFTPDirectory
呼び出すと、次のことができます。.getdata
ftplib.FTP
directory_filenames= [ftpfile.name for ftpfile in ftpd.files]
私はそれがあなたのために働くはずだと信じています。
file_name_list = [' '.join(each_file.split()).split()[-1] for each_file_detail in file_list_from_log]
ノート -
ここでは、コンソールではなく、プログラム(リストとして)にデータが必要であると想定しています。
each_file_detailは、プログラムによって生成されている各行です。
'' .join(each_file.split())
複数のスペースを1つのスペースに置き換えます。