リモート ftp 上のファイルがフォルダーであるか、ftplib を使用していないかを確認するにはどうすればよいですか?
私が今持っている最善の方法は、nlstを実行し、各ファイルでサイズを呼び出すことを繰り返すことです.ファイルがエラーになった場合、それはフォルダですか?
より良い方法はありますか?約 12 の異なる ftp サーバー (多くは非常に古いもの) があるため、list の出力を解析できません。
私は何をすべきか?
ftplib には「isdir」と「isfile」の定義はありません。ftplibを使用する必要がない場合は、ftputilを使用することをお勧めします。
まず、ftputil パッケージをインストールする必要があります。これを実現するには、次のコマンドを使用しますpython -m pip install ftputil
。インストール後、ライブラリをコードにインポートできます。十分な説明だと思います。それでは、実装に行きましょう:
import ftputil
with ftputil.FTPHost("host", "username", "password") as ftp_host:
ftp_host.chdir("/directory/")
list = ftp_host.listdir(ftp_host.curdir)
for fname in list:
if ftp_host.path.isdir(fname):
print(fname + " is a directory")
else:
print(fname + " is not a directory")
FTP は非常に初歩的なプロトコルであり、各ノードのタイプ (ファイル、ディレクトリ) を取得できる組み込みのプロトコル クエリがないため、見つけたようなヒューリスティックが唯一の解決策です。
各ノードのサイズを取得できない場合は、それらのノードのそれぞれで呼び出すことを検討する必要FTP.nlst()
があります。エラーが発生するのはディレクトリではなくファイルです。
FTP.dir
ディレクトリのリストを返します。これをコールバック関数で解析して、ディレクトリであるかどうかを確認できます。たとえば、次のようにします。
def parse(line):
if line[0] == 'd':
print(line.rpartition(' ')[2]) # gives you the name of a directory
ftp.dir(parse)
def is_file(filename):
return ftp.size(filename) is not None
ディレクトリの場合、ftp.size は None を返すため、これは機能します。
MLST コマンドを使用できます。
import ftplib
f = ftplib.FTP()
f.connect("localhost")
f.login()
print f.sendcmd('MLST /')
pyftpdlibサーバーに対して、上記のコードは以下を出力します。
250-Listing "/":
modify=20111212124834;perm=el;size=12288;type=dir;unique=807g100001; /
250 End MLST.
あなたがしなければならないことは、その文字列を解析し、「type = dir」または「type = cdir」(「。」のような現在のディレクトリ)または「type = pdir」(「..」のような親ディレクトリ)を探すことです。正規表現。一致した場合は、指定されたパスがディレクトリを参照していることを意味します。
これは、特定のディレクトリ内のディレクトリを見つけるために使用するものです。プログラムの後半でセットを使用するため、ディレクトリ名をセットとして返しますが、最後にセットの作成を省略して、ディレクトリ名をリスト、タプルなどとして返すこともできます。
def get_directories(ftp_server):
"""
Returns a set of directories in the current directory on the FTP server
Stdout output of ftp_server.dir() is redirected to an IO object and then
reset, because ftp_server.dir() only prints its results to stdout.
@param ftp_server: Open connection to FTP server
@return: Set of directory names
"""
# Redirect stdout
old_stdout = sys.stdout
sys.stdout = new_stdout = StringIO()
# Get directory listing
ftp_server.dir()
# Reset stdout
sys.stdout = old_stdout
directory_listing = new_stdout.getvalue().split("\n")
# Directories are listed starting with "d" for "directory"
only_directories = (x for x in directory_listing if x.startswith("d"))
# This only deals with directory names without spaces.
directory_names = set(dirname.split()[-1] for dirname in only_directories)
return directory_names
def is_file(filename):
current = ftp.pwd()
try:
ftp.cwd(filename)
except:
ftp.cwd(current)
return True
ftp.cwd(current)
return False
ここに別の解決策があります。書き途中で、問題があることに気づきました。フォルダに変更する権限がない場合は、代わりにファイルとして読み込まれます。任意のフォルダにアクセスできる場合に機能します。
多分それはいくつかのアイデアを与えるかもしれないので、私はまだそれを投稿しました.
私はftplibを扱うときにこれを使用しました:
import ftplib
from ftplib import FTP
ftp=FTP("ftp address")
ftp.login("user","password")
path = "/is/this/a/file/or/a/folder/"
try:
ftp.cwd(path)
print "it's a folder!"
except ftplib.error_perm:
print "it's not a folder!"
解決策を見つけましたが、最善ではない可能性があり、お役に立てると思います。
> def isfile(remote_name):
> try:
> ftp.sendcmd('MDTM ' + remote_name)
> except:
> return False
> else:
> return True
この関数は、「remote_name」が通常のファイルの場合に TRUE を返し、それ以外の場合は False を返します。
この関数は、 がファイルのTrue
場合は を返し、そうでない場合は を返します。object
False
def _is_file(FTP, object):
if FTP.nlst(object) == [object]:
return True
else:
return False
使用例:
import ftplib
with ftplib.FTP(host=ftp_link, user=ftp_username, passwd=ftp_password) as FTP:
if _is_file(FTP, object='/path/filename.extention'):
print(object, 'is file!')
else:
print(object, 'is directory!')
FTP.nlst()はどのように機能しますか?
FTP.nlst(object)
[object]
がファイルの場合に返しobject
ます。FTP.nlst(object)
object
が空のフォルダの場合、空のリストを返します。FTP.nlst(object)
object
がファイルまたはディレクトリを含むフォルダである場合、文字列のリストを返します。すべてのファイルには拡張子があるため、split('.') を使用すると、サイズ 2 のリストに分割できます。一方、ディレクトリの場合、split('.') を使用した後のリストのサイズは 1 になります。したがって、リストのサイズを確認することで、ファイルかディレクトリかを識別できます。
os.chdir(r"path")
ftp = ftplib.FTP('ftp.some.server')
ftp.login('username','password')
filelist=ftp.nlst()
for file in filelist:
fildir=file.split('.')
filsize=len(fildir)
if(filsize>1):
ftp.retrbinary('RETR %s' %file, open(file, 'wb').write)
ftp.close()