ftplib.FTP.nlst()

2025-06-06

以下に詳しく説明します。

役割

nlst() メソッドは、FTPサーバーに対して NLST コマンドを送信します。このコマンドは、指定されたディレクトリにあるファイルやサブディレクトリの名前のみをリストアップします。詳細な情報(ファイルサイズ、更新日時、パーミッションなど)は含まれません。

構文

FTP.nlst(argument)
  • argument (オプション): リストアップしたいディレクトリのパスを指定します。省略した場合、現在の作業ディレクトリの内容がリストアップされます。

戻り値

成功した場合、指定されたディレクトリにあるファイルやサブディレクトリの名前(文字列)のリストを返します。リストの各要素はファイル名またはディレクトリ名です。

以下に簡単な使用例を示します。

from ftplib import FTP

try:
    # FTPサーバーに接続
    ftp = FTP('your_ftp_server.com') # ご自身のFTPサーバーのアドレスに置き換えてください
    ftp.login('your_username', 'your_password') # ご自身のユーザー名とパスワードに置き換えてください

    # 現在のディレクトリのファイルとディレクトリ名をリストアップ
    file_list = ftp.nlst()
    print("現在のディレクトリのファイルとディレクトリ:")
    for item in file_list:
        print(item)

    # 特定のディレクトリのファイルとディレクトリ名をリストアップ (例: 'public_html' ディレクトリ)
    # サーバーによってはパスの指定方法が異なる場合があります
    try:
        public_html_list = ftp.nlst('public_html')
        print("\n'public_html' ディレクトリのファイルとディレクトリ:")
        for item in public_html_list:
            print(item)
    except Exception as e:
        print(f"\n'public_html' ディレクトリのリストアップ中にエラーが発生しました: {e}")


except Exception as e:
    print(f"FTP接続または操作中にエラーが発生しました: {e}")
finally:
    if 'ftp' in locals() and ftp.sock: # ftp オブジェクトが存在し、ソケットが開いていることを確認
        ftp.quit() # 接続を閉じる
        print("FTP接続を閉じました。")

nlst() と dir()/mlsd() の違い

ftplib には、ディレクトリの内容をリストアップするための類似のメソッドがいくつかあります。

  • mlsd(): MLSD コマンドを送信します。これは機械で読み取りやすい(machine-readable)形式で、標準化されたファイルやディレクトリの情報を返します。より現代的で推奨される方法です。
  • dir(): LIST コマンドを送信し、より詳細な情報(パーミッション、所有者、グループ、ファイルサイズ、更新日時など)を含むリストを返します。この出力形式はFTPサーバーによって異なるため、パースするのが難しい場合があります。
  • nlst(): ファイル名やディレクトリ名のみをリストアップします。最もシンプルな形式です。


接続関連のエラー

nlst() を呼び出す前に、FTPサーバーに正常に接続し、認証を完了している必要があります。これらの段階で問題が発生している場合、nlst() は実行されません。

  • ftplib.error_perm: 530 Login authentication failed.

    • 原因: ユーザー名またはパスワードが間違っているため、ログインに失敗した場合に発生します。
    • トラブルシューティング:
      • ユーザー名とパスワードの確認: 正しいユーザー名とパスワードを使用していることを厳重に確認します。大文字と小文字の区別も重要です。
      • 匿名FTP: 匿名FTPサーバーに接続している場合、ユーザー名を 'anonymous'、パスワードをメールアドレス(例: '[email protected]')として試します。
    • 原因: FTPサーバーへの接続に失敗した場合に発生します。
      • FTPサーバーのホスト名またはIPアドレスが間違っている。
      • 指定されたポート(デフォルトは21)でFTPサーバーが稼働していない。
      • ファイアウォール(クライアント側、サーバー側、またはネットワーク経路上のもの)が接続をブロックしている。
      • DNS解決の問題。
      • ネットワーク接続がない。
    • トラブルシューティング:
      • ホスト名/IPアドレスとポートの確認: 正しいFTPサーバーのホスト名またはIPアドレス、およびポート番号(通常は21)を使用していることを確認します。
      • FTPクライアントでのテスト: FileZillaなどの一般的なFTPクライアントを使用して、同じサーバーに接続できるか試します。これにより、FTPサーバー自体が正常に動作しているか、またはネットワークの問題があるかを切り分けられます。
      • ファイアウォールの確認: サーバーおよびクライアントのファイアウォール設定を確認し、FTP(ポート21/TCPとデータポート)が許可されていることを確認します。特に、FTPは「アクティブモード」と「パッシブモード」という2つのデータ転送モードがあり、パッシブモードではデータ接続のためにクライアントがランダムなポートを開く必要があります。ファイアウォールがこれをブロックする場合があります。
      • タイムアウト設定: ftplib.FTP のコンストラクタや connect() メソッドで timeout パラメータを設定し、適切なタイムアウト時間を設けます。
      • DNSの問題: ホスト名で接続できない場合、代わりにIPアドレスを直接指定してみます。

nlst() 実行時のエラー

接続と認証が成功した後でも、nlst() の呼び出し自体でエラーが発生することがあります。

  • nlst() が空のリストを返す場合

    • 原因:
      • 指定されたディレクトリにファイルやサブディレクトリが本当に存在しない。
      • FTPサーバーが NLST コマンドに対してファイルやサブディレクトリを返さない設定になっている、または古いサーバーで NLST がディレクトリをリストしない。
      • ワイルドカード(例: ftp.nlst('*.txt'))を使用しているが、マッチするファイルがない、またはサーバーがワイルドカードを正しく解釈できない。
    • トラブルシューティング:
      • ディレクトリの内容確認: FTPクライアント(FileZillaなど)で実際にそのディレクトリの内容を確認し、本当にファイルがないのか、それともPythonコードの問題なのかを切り分けます。
      • dir() または mlsd() の使用: nlst() が空のリストを返す場合でも、ftp.dir()ftp.mlsd()(より詳細な情報を含む)が機能することがあります。これらのメソッドは異なるFTPコマンド(LISTMLSD)を使用するため、サーバーの実装の違いによる問題を回避できる場合があります。
        • ftp.dir() は行ごとに文字列を返すため、パースが必要になることが多いです。
        • ftp.mlsd() は機械可読な形式で、より構造化された情報を返します(ただし、すべてのサーバーが MLSD に対応しているわけではありません)。
  • ftplib.error_perm: 501 Syntax error in parameters or arguments.

    • 原因: nlst() に無効な引数を渡した場合、またはFTPサーバーが NLST コマンドの引数としてパスを処理できない場合に発生します。
    • トラブルシューティング:
      • 引数の形式: nlst() に渡すパスが正しい形式であることを確認します。例えば、ワイルドカード(*)の解釈はFTPサーバーによって異なる場合があります。
      • サーバーの実装: FTPサーバーによっては、NLST コマンドが引数を受け付けない、または特定の形式しか受け付けない場合があります。その場合、まず ftp.cwd() で目的のディレクトリに移動してから ftp.nlst()(引数なし)を呼び出すことを検討します。
  • ftplib.error_perm: 550 <directory>: No such file or directory.

    • 原因:
      • nlst('some/path') のように引数にパスを指定した場合、そのパスが存在しない。
      • 指定されたディレクトリへのアクセス権限がない。
    • トラブルシューティング:
      • パスの確認: 指定したディレクトリのパスがFTPサーバー上に実際に存在し、かつ正しいことを確認します。絶対パスと相対パスのどちらを使用しているかにも注意してください。
      • 権限の確認: ログインしているユーザーがそのディレクトリにアクセスする権限を持っているか確認します。
      • 現在のディレクトリの確認: ftp.pwd() を使用して現在の作業ディレクトリを確認し、そこから相対パスが正しいか検証します。

共通のトラブルシューティングのヒント

  • FTPサーバーのバージョンと設定: 使用しているFTPサーバーの種類(例: vsftpd, Pure-FTPd, Windows IIS FTPなど)とバージョン、およびその設定(特にパッシブモードやファイアウォールの設定)を確認します。サーバー側の設定がクライアントの動作に大きく影響することがあります。
  • クリーンアップ: 処理の最後に ftp.quit() または ftp.close() を呼び出して、FTP接続を適切に閉じるようにします。これは、finally ブロックで行うのが一般的です。
  • 例外処理: try...except ブロックを使用して、ftplib.all_errors をキャッチし、エラーメッセージを正確に出力するようにします。これにより、予期しないエラーが発生した場合でも、原因を把握しやすくなります。
  • デバッグレベルの設定: ftp.set_debuglevel(1) または ftp.set_debuglevel(2) を呼び出すことで、ftplib がFTPサーバーとの通信内容(送信されたコマンドと受信した応答)をコンソールに出力します。これにより、どのようなFTPコマンドが送信され、どのような応答が返されているかを詳細に確認でき、問題の特定に非常に役立ちます。


ftplib.FTP.nlst() は、FTPサーバー上のディレクトリにあるファイルやサブディレクトリの名前だけをリストアップする際に使用します。詳細な情報(サイズ、日付、パーミッションなど)は含まれません。

基本的な使い方:現在のディレクトリのリストアップ

この例では、FTPサーバーに接続し、ログインした後、現在の作業ディレクトリにあるすべてのファイルとディレクトリの名前を取得します。

from ftplib import FTP

# FTPサーバーへの接続情報
#  ご自身のFTPサーバーの情報に置き換えてください 
FTP_HOST = 'your_ftp_server.com'
FTP_USERNAME = 'your_username'
FTP_PASSWORD = 'your_password'

ftp = None # ftpオブジェクトの初期化

try:
    # 1. FTPサーバーに接続
    print(f"FTPサーバー '{FTP_HOST}' に接続中...")
    ftp = FTP(FTP_HOST)

    # 2. ログイン
    print(f"ユーザー '{FTP_USERNAME}' でログイン中...")
    ftp.login(FTP_USERNAME, FTP_PASSWORD)
    print("ログイン成功!")

    # 3. 現在の作業ディレクトリのコンテンツをnlst()で取得
    print("\n現在のディレクトリのファイルとディレクトリをリストアップ中 (nlst()...")
    file_names = ftp.nlst()

    # 4. 取得した名前を順に表示
    if file_names:
        print("--- リスト開始 ---")
        for name in file_names:
            print(name)
        print("--- リスト終了 ---")
    else:
        print("現在のディレクトリにはファイルやディレクトリがありません。")

except Exception as e:
    # エラーハンドリング
    print(f"エラーが発生しました: {e}")

finally:
    # 接続を閉じる (重要!)
    if ftp:
        print("FTP接続を閉じます。")
        ftp.quit()

解説

  • ftp.quit(): FTPセッションを終了し、接続を閉じます。これは非常に重要で、リソースのリークを防ぎます。
  • ftp.nlst(): 現在のFTP作業ディレクトリ内のファイルやサブディレクトリの名前のリストを返します。
  • ftp.login(FTP_USERNAME, FTP_PASSWORD): 指定されたユーザー名とパスワードでログインします。
  • FTP(FTP_HOST): 指定されたホスト名でFTPサーバーに接続します。

特定のディレクトリのリストアップ

nlst() メソッドに引数としてパスを渡すことで、指定したディレクトリのコンテンツをリストアップできます。

from ftplib import FTP

# FTPサーバーへの接続情報
FTP_HOST = 'your_ftp_server.com'
FTP_USERNAME = 'your_username'
FTP_PASSWORD = 'your_password'

# リストアップしたいディレクトリのパス
TARGET_DIRECTORY = 'public_html' # 例: public_html フォルダ

ftp = None

try:
    print(f"FTPサーバー '{FTP_HOST}' に接続中...")
    ftp = FTP(FTP_HOST)
    print(f"ユーザー '{FTP_USERNAME}' でログイン中...")
    ftp.login(FTP_USERNAME, FTP_PASSWORD)
    print("ログイン成功!")

    # 特定のディレクトリのコンテンツをnlst()で取得
    print(f"\nディレクトリ '{TARGET_DIRECTORY}' のファイルとディレクトリをリストアップ中 (nlst()...")
    # nlst() にパスを渡して、そのディレクトリの内容を取得
    # サーバーによっては、パスの指定方法に注意が必要な場合があります (例: /path/to/dir)
    target_dir_items = ftp.nlst(TARGET_DIRECTORY)

    if target_dir_items:
        print(f"--- '{TARGET_DIRECTORY}' のリスト開始 ---")
        for item in target_dir_items:
            # サーバーから返される名前は、TARGET_DIRECTORYからの相対パスかもしれません
            # その場合、例えば 'public_html/index.html' のように表示されます
            print(item)
        print(f"--- '{TARGET_DIRECTORY}' のリスト終了 ---")
    else:
        print(f"ディレクトリ '{TARGET_DIRECTORY}' は空であるか、存在しませんでした。")

except Exception as e:
    print(f"エラーが発生しました: {e}")

finally:
    if ftp:
        print("FTP接続を閉じます。")
        ftp.quit()

解説

  • ftp.nlst(TARGET_DIRECTORY): TARGET_DIRECTORY で指定されたパスのファイルやディレクトリの名前をリストアップします。サーバーの構成によっては、返されるアイテムが指定されたパスからの相対パスで表示される場合があります(例:'public_html/image.jpg')。

FTP通信はネットワークやサーバーの設定に左右されるため、エラーハンドリングは非常に重要です。set_debuglevel() を使うと、デバッグに役立つ情報が得られます。

from ftplib import FTP, all_errors

# FTPサーバーへの接続情報 (意図的に間違った情報を入れるなどしてエラーを試すことができます)
FTP_HOST = 'non_existent_server.com' # 存在しないサーバーでエラーを試す
FTP_USERNAME = 'wrong_user'
FTP_PASSWORD = 'wrong_password'

ftp = None

try:
    print(f"FTPサーバー '{FTP_HOST}' に接続中...")
    ftp = FTP(FTP_HOST)

    # デバッグレベルを設定 (1: コマンドと応答を表示, 2: さらにソケットの詳細も表示)
    # これにより、FTPサーバーとの通信内容がコンソールに出力され、問題解決に役立ちます
    ftp.set_debuglevel(2)

    print(f"ユーザー '{FTP_USERNAME}' でログイン中...")
    ftp.login(FTP_USERNAME, FTP_PASSWORD)
    print("ログイン成功!")

    print("\n現在のディレクトリのファイルとディレクトリをリストアップ中 (nlst()...")
    file_names = ftp.nlst()

    if file_names:
        print("--- リスト開始 ---")
        for name in file_names:
            print(name)
        print("--- リスト終了 ---")
    else:
        print("現在のディレクトリにはファイルやディレクトリがありません。")

# ftplib関連の全てのエラーをキャッチ
except all_errors as e:
    print(f"\nftplibエラーが発生しました: {e}")
    # 例外メッセージから具体的なエラーコードや内容を読み取ります
    # 例: '530 Login authentication failed.' (ログイン失敗)
    # 例: '[Errno -2] Name or service not known' (ホスト名解決失敗)

except Exception as e:
    # その他の予期せぬエラーをキャッチ
    print(f"\n予期せぬエラーが発生しました: {e}")

finally:
    if ftp:
        print("FTP接続を閉じます。")
        ftp.quit()
  • finally ブロック: エラーが発生したかどうかにかかわらず、ftp.quit() が確実に呼び出されるようにします。これにより、開かれたFTP接続が適切に閉じられ、リソースが無駄に消費されるのを防ぎます。
  • except all_errors as e: ftplib モジュールが生成するすべての例外をキャッチするための包括的な方法です。これにより、接続エラー、認証エラー、コマンド実行エラーなど、さまざまなFTP関連のエラーに対応できます。
  • ftp.set_debuglevel(2): この行を追加することで、PythonのFTPクライアントがサーバーとどのようなコマンドをやり取りしているかがコンソールに表示されます。これにより、接続の問題、ログインの問題、コマンドの失敗などが具体的にわかるようになり、トラブルシューティングに非常に役立ちます。


主に以下の2つの代替メソッドがあります。

  1. ftplib.FTP.dir(): 詳細なリスト表示(LIST コマンド)
  2. ftplib.FTP.mlsd(): 機械可読な詳細リスト表示(MLSD コマンド)

それぞれについて詳しく見ていきましょう。

ftplib.FTP.dir() - 詳細なリスト表示

特徴

  • 戻り値: 戻り値は None です。代わりに、リストの各行を処理するコールバック関数を渡すか、デフォルトでは標準出力にプリントされます。
  • 引数: nlst() と同様に、オプションでパスを渡すことができます。
  • 出力形式の多様性: FTPサーバーの実装(UNIX系、Windows系など)によって出力フォーマットが大きく異なるため、プログラムでパースするのが難しい場合があります。正規表現などを用いて手動でパースする必要があります。

基本的な使い方(コールバック関数を使用しない場合)

from ftplib import FTP

# FTPサーバーへの接続情報
FTP_HOST = 'your_ftp_server.com'
FTP_USERNAME = 'your_username'
FTP_PASSWORD = 'your_password'

ftp = None

try:
    ftp = FTP(FTP_HOST)
    ftp.login(FTP_USERNAME, FTP_PASSWORD)
    print("ログイン成功!")

    print("\n現在のディレクトリの詳細リスト (dir())...")
    # dir() はデフォルトで結果を標準出力にプリントします
    ftp.dir() # ここでリストが表示される

    print("\n特定のディレクトリ ('public_html') の詳細リスト (dir())...")
    ftp.dir('public_html') # 特定のディレクトリも指定可能

except Exception as e:
    print(f"エラーが発生しました: {e}")
finally:
    if ftp:
        ftp.quit()

コールバック関数を使用した使い方(よりプログラマティック)

dir() は、各行を処理するためのコールバック関数を受け取ります。これにより、リストの内容をプログラムでキャプチャし、処理することができます。

from ftplib import FTP

FTP_HOST = 'your_ftp_server.com'
FTP_USERNAME = 'your_username'
FTP_PASSWORD = 'your_password'

# リストの各行を保存するためのリスト
dir_listing = []

def handle_dir_line(line):
    """dir() の各行を処理するコールバック関数"""
    dir_listing.append(line)

ftp = None

try:
    ftp = FTP(FTP_HOST)
    ftp.login(FTP_USERNAME, FTP_PASSWORD)
    print("ログイン成功!")

    print("\n現在のディレクトリの詳細リストをコールバック関数で取得中...")
    ftp.dir(callback=handle_dir_line)

    print("\n--- 取得した詳細リスト ---")
    for item in dir_listing:
        print(item)
    print("--- リスト終了 ---")

    # 例: ファイルサイズやパーミッションをパースする(非常に単純な例)
    # 実際のパースはサーバーの出力形式に依存し、より複雑になります
    print("\n--- パースの例 ---")
    for line in dir_listing:
        parts = line.split()
        if len(parts) > 8: # 最低限の項目があるか確認
            permissions = parts[0]
            size = parts[4]
            name = " ".join(parts[8:]) # ファイル名にはスペースが含まれる場合がある
            print(f"パーミッション: {permissions}, サイズ: {size}, 名前: {name}")

except Exception as e:
    print(f"エラーが発生しました: {e}")
finally:
    if ftp:
        ftp.quit()

dir() の考慮事項

  • 非推奨: FTPサーバーが MLSD コマンドに対応している場合は、後述の mlsd() を使用することが推奨されます。
  • パースの複雑さ: 前述の通り、出力形式がサーバー依存であるため、堅牢なパースロジックを実装するのが難しいです。

ftplib.FTP.mlsd() メソッドは、FTPサーバーの MLSD コマンドに対応しています。これは、機械で読み取りやすい(machine-readable)形式で、標準化されたファイルやディレクトリの情報を返します。これは LIST コマンドの問題(出力形式の多様性)を解決するために導入されました。

特徴

  • 戻り値: イテレータを返します。各イテレーションで (filename, facts_dict) の形式でデータが得られます。
  • 現代的: 最近のFTPサーバーは MLSD に対応していることが多いですが、古いサーバーでは対応していない場合があります。
  • 標準化: MLSD コマンドの出力形式はRFCで標準化されているため、異なるFTPサーバー間でも一貫性があります。
  • 構造化されたデータ: 各アイテムはタプル (filename, facts) として返され、facts はキーと値のペアを含む辞書です。これにより、プログラムでデータにアクセスしやすくなります。

基本的な使い方

from ftplib import FTP

FTP_HOST = 'your_ftp_server.com'
FTP_USERNAME = 'your_username'
FTP_PASSWORD = 'your_password'

ftp = None

try:
    ftp = FTP(FTP_HOST)
    ftp.login(FTP_USERNAME, FTP_PASSWORD)
    print("ログイン成功!")

    print("\n現在のディレクトリのファイルとディレクトリを機械可読形式でリストアップ中 (mlsd())...")
    # mlsd() はイテレータを返すので、forループで処理します
    for filename, facts in ftp.mlsd():
        print(f"ファイル名: {filename}")
        print("  属性:")
        for key, value in facts.items():
            print(f"    {key}: {value}")
        print("-" * 20)

    # 特定のディレクトリのmlsd
    # print("\n特定のディレクトリ ('public_html') の mlsd()...")
    # for filename, facts in ftp.mlsd('public_html'):
    #     print(f"ファイル名: {filename}, 属性: {facts}")

except Exception as e:
    print(f"エラーが発生しました: {e}")
finally:
    if ftp:
        ftp.quit()

mlsd() で取得できる可能性のある主な facts (属性) の例

  • UNIX.uid, UNIX.gid: UNIXユーザーID、グループID
  • UNIX.mode: UNIX形式のパーミッション(例: 0755
  • perm: パーミッション(例: r, w, a, d, f, l, m, p
  • modify: 最終更新日時 (UTC)
  • size: ファイルサイズ (バイト単位)
  • type: file, dir, cdir (現在のディレクトリ), pdir (親ディレクトリ)

mlsd() の考慮事項

  • 堅牢性: dir() よりも格段にパースが容易で、信頼性が高いです。
  • サーバー対応: 古いFTPサーバーでは MLSD コマンドに対応していない場合があります。その場合は dir()nlst() を使用する必要があります。
メソッド取得する情報出力形式特徴/備考推奨されるケース
FTP.nlst()ファイル/ディレクトリ名のみ文字列のリスト最もシンプル。詳細情報は含まない。ファイル/ディレクトリの存在確認や名前の一覧だけで良い場合。
FTP.dir()詳細情報不定形な文字列(行)サーバー依存の出力形式。パースが難しい。主にコールバックで使用。古いFTPサーバーで MLSD がサポートされていないが、詳細情報が必要な場合。デバッグ目的。
FTP.mlsd()詳細情報構造化された辞書RFC標準化。機械可読。新しいFTPサーバーでサポートされる。最も推奨される方法。FTPサーバーが MLSD に対応しており、詳細情報をプログラムで処理したい場合。
  1. 最初に mlsd() を試す: 詳細な情報をプログラムで処理するのに最も適しているためです。
  2. mlsd() が失敗した場合: MLSD コマンドがサポートされていない可能性があります。この場合、dir() を試すことを検討します。ただし、dir() の出力のパースは複雑になることを覚悟してください。
  3. 名前だけが必要な場合: nlst() を使用します。