ftplib.FTP.size()
2025-06-06
以下に詳しく説明します。
ftplib.FTP.size(filename)
- 注意点
size()
メソッドはファイルに対してのみ機能し、ディレクトリのサイズを取得することはできません。- すべてのFTPサーバーが
SIZE
コマンドをサポートしているわけではありません。一部の古いサーバーや特定の構成のサーバーでは、このコマンドが機能しない場合があります。その場合、ファイルのサイズを取得するには、ファイルをダウンロードしてからローカルでサイズを確認するなどの別の方法を検討する必要があります。 - バイナリモード(
TYPE I
)に設定してからsize()
を呼び出すことが推奨されます。これにより、サーバーがファイルサイズを正しく解釈できるようになります。
- 戻り値
- 成功した場合、ファイルのサイズがバイト単位の整数で返されます。
- FTPサーバーが
SIZE
コマンドをサポートしていない場合、またはファイルが見つからない場合、None
が返されることがあります。
- 引数
filename
: サイズを取得したいファイルの名前(文字列)を指定します。
- 目的
FTPサーバー上のfilename
で指定されたファイルのサイズを問い合わせます。
None が返される
最も一般的なケースで、size()
メソッドが None
を返すことがあります。これはエラーではありませんが、期待するファイルサイズが得られない状況です。
-
トラブルシューティング
- ftp.sendcmd('TYPE I') を試す
size()
を呼び出す前に、明示的にバイナリモードに設定してみてください。ftp.sendcmd('TYPE I') file_size = ftp.size(file_name)
- ファイルパスの確認
ftp.nlst()
やftp.dir()
を使って、実際にサーバー上のファイルリストを確認し、ファイル名やパスが正しいことを確認します。 - FTPサーバーのドキュメントを確認
使用しているFTPサーバーがSIZE
コマンドをサポートしているか、特定の要件があるかを確認します。 - 別の方法を検討する
SIZE
コマンドがサポートされていない場合、ファイルを一時的にダウンロードしてローカルでサイズを確認する、またはサーバーが提供する別のメタデータ取得方法(もしあれば)を探す必要があります。ただし、大きなファイルをダウンロードするのは効率的ではありません。
- ftp.sendcmd('TYPE I') を試す
-
- FTPサーバーが SIZE コマンドをサポートしていない
SIZE
コマンドはFTPプロトコルの標準コマンドではありません。多くのFTPサーバーがサポートしていますが、一部の古いサーバーや特定のサーバー実装ではサポートされていない場合があります。 - ファイルが存在しない/パスが間違っている
指定したファイル名やパスがサーバー上に存在しない場合、None
が返されます。大文字小文字の区別も考慮する必要があります。 - 権限がない
ユーザーにそのファイルのサイズを取得する権限がない場合。 - バイナリモードになっていない
一部のサーバーでは、SIZE
コマンドを使用する前にバイナリモード(TYPE I
)に設定する必要があります。ASCIIモード(TYPE A
)のままだと、正しくサイズを取得できない場合があります。
- FTPサーバーが SIZE コマンドをサポートしていない
ftplib.error_perm (5xx エラー)
ftplib.error_perm
例外は、サーバーが永続的なエラー(通常は5xx系の応答コード)を返した場合に発生します。
-
トラブルシューティング
- ファイルパスと権限の確認
まず、ファイルパスが正確であること、そしてログインしているユーザーがそのファイルにアクセスする権限を持っていることを確認します。 - set_debuglevel() でデバッグ情報を取得
ftp.set_debuglevel(2)
を設定すると、FTPコマンドのやり取りが詳細に表示されます。これにより、サーバーからの正確なエラーメッセージ(応答コードとテキスト)を確認でき、問題の原因を特定するのに役立ちます。import sys from ftplib import FTP, all_errors try: ftp = FTP('ftp.example.com') ftp.set_debuglevel(2) # デバッグレベルを2に設定 ftp.login('username', 'password') ftp.sendcmd('TYPE I') file_name = 'non_existent_file.txt' file_size = ftp.size(file_name) # ... except all_errors as e: print(f"FTPエラー: {e}", file=sys.stderr)
- FTPサーバーのログを確認
サーバーサイドで何が起きているかを確認するために、FTPサーバーのログを調べることが非常に有効です。
- ファイルパスと権限の確認
-
原因
- ファイルが見つからない (550 Requested action not taken: File not found など)
指定したファイル名やパスがサーバー上に存在しない。 - 権限の問題 (550 Permission denied など)
ユーザーにそのファイルへのアクセス権限がない。 - 無効なコマンド (500 Syntax error, command unrecognized など)
サーバーがSIZE
コマンドを認識しない。これはNone
が返される場合と似ていますが、サーバーによっては明確なエラーを返すことがあります。
- ファイルが見つからない (550 Requested action not taken: File not found など)
接続関連のエラー
size()
を呼び出す前に、そもそもFTPサーバーへの接続が確立されていない、または途中で切断された場合に発生するエラーです。
-
トラブルシューティング
- 接続情報の確認
ホスト名、ポート(デフォルトは21)、ユーザー名、パスワードが正しいことを再確認します。 - ファイアウォールの確認
クライアント側、サーバー側、またはその間のネットワーク機器のファイアウォールがFTP接続(特にデータ接続)をブロックしていないか確認します。 - timeout パラメータの使用
FTP()
オブジェクトの作成時やconnect()
メソッドでタイムアウトを設定し、応答がない場合にプログラムがハングアップするのを防ぎます。ftp = FTP('ftp.example.com', timeout=60) # 60秒のタイムアウト
- try...except ftplib.all_errors
ほとんどのFTP関連のエラーをキャッチするために、包括的な例外ハンドリングを使用します。
- 接続情報の確認
-
原因
- 接続失敗
ホスト名、ポート、認証情報が間違っている。 - ネットワークの問題
ファイアウォール、ネットワーク障害、タイムアウトなど。 - アイドルタイムアウト
接続が長時間アイドル状態だったためにサーバーによって切断された。
- 接続失敗
-
トラブルシューティング
- FTP オブジェクトの encoding パラメータ
Python 3では、ftplib.FTP
のコンストラクタでencoding
パラメータを指定できます。ftp = FTP('ftp.example.com', encoding='shift_jis') # または 'euc-jp', 'utf-8' など
- サーバーの文字コードを特定
多くのFTPサーバーはUTF-8をサポートしていますが、古いサーバーではShift_JISやEUC-JPが使用されている場合があります。サーバー管理者に確認するか、一般的な文字コードを試してみてください。
- FTP オブジェクトの encoding パラメータ
-
原因
- FTPサーバーとクライアントの文字コードの不一致
FTPプロトコル自体は文字コードを規定していません。サーバーが期待する文字コードとPythonコードで使用している文字コードが異なる場合、ファイル名が正しく解釈されません。
- FTPサーバーとクライアントの文字コードの不一致
ftplib.FTP.size()
のトラブルシューティングのキーポイントは以下の通りです。
ftp.set_debuglevel(2)
で詳細なログを確認する。 これが最も重要で、サーバーからの具体的な応答を確認できます。ftp.sendcmd('TYPE I')
でバイナリモードに設定する。- ファイル名とパスが正確であることを確認する。
- FTPサーバーが
SIZE
コマンドをサポートしているか確認する。 - 権限の問題ではないか確認する。
try...except ftplib.all_errors
で例外を適切に処理する。- 必要に応じて文字コード設定を試す。
最もシンプルな例です。ファイルが存在し、サーバーが SIZE
コマンドをサポートしている場合に機能します。
ftplib.FTP.size()
が使えない/使わない場合
- FTPサーバーが
SIZE
コマンドをサポートしていない ftplib.FTP.size()
がNone
を返す、またはerror_perm
を返す- より詳細なファイル情報(最終更新日時、パーミッションなど)も同時に取得したい
このような場合に、以下の方法を検討できます。
ftplib.FTP.mlsd() を使用する (推奨される代替手段)
mlsd()
(Machine Readable List Directory) コマンドは、FTPプロトコルの比較的新しい拡張機能であり、ファイルに関する構造化された情報を取得できます。これにより、ファイルのサイズだけでなく、タイプ(ファイルかディレクトリか)、最終更新日時、パーミッションなどを効率的に取得できます。
mlsd()
は、イテレータを返し、各要素は (ファイル名, 属性の辞書)
のタプルです。属性の辞書に 'size'
キーが含まれていれば、それがファイルのサイズです。
利点
- 多くの場合、
SIZE
コマンドよりも信頼性が高い。 - ファイルとディレクトリの区別が容易。
size()
よりも多くの情報(タイプ、日時など)を一度に取得できる。
欠点
- すべてのFTPサーバーが
MLSD
コマンドをサポートしているわけではない(比較的モダンなサーバーでのみ利用可能)。
コード例
from ftplib import FTP, all_errors
import sys
FTP_HOST = 'ftp.example.com'
FTP_USER = 'your_username'
FTP_PASS = 'your_password'
TARGET_DIR = '/' # 調査対象のディレクトリ
print(f"FTPサーバー: {FTP_HOST}")
print(f"対象ディレクトリ: {TARGET_DIR}")
ftp = None
try:
ftp = FTP(FTP_HOST)
ftp.login(FTP_USER, FTP_PASS)
ftp.sendcmd('TYPE I') # バイナリモード推奨
print(f"ディレクトリ '{TARGET_DIR}' の内容を MLSD で取得中...")
# ディレクトリを移動
ftp.cwd(TARGET_DIR)
file_info_list = []
# mlsd() はイテレータを返す
for name, attrs in ftp.mlsd():
# 'type' 属性でファイルかディレクトリかを判別
if attrs.get('type') == 'file':
# 'size' 属性が存在すれば、それがサイズ
size = attrs.get('size')
if size:
file_info_list.append((name, int(size)))
else:
file_info_list.append((name, "サイズ情報なし"))
elif attrs.get('type') == 'dir':
file_info_list.append((name + '/', "ディレクトリ"))
else:
file_info_list.append((name, "不明なタイプ"))
print("\n--- MLSD によるファイルサイズ情報 ---")
for name, size_info in file_info_list:
if isinstance(size_info, int):
print(f" {name:<30}: {size_info} バイト ({size_info / (1024 * 1024):.2f} MB)")
else:
print(f" {name:<30}: {size_info}")
print("---------------------------------------")
except all_errors as e:
print(f"エラー: FTP操作中に問題が発生しました: {e}", file=sys.stderr)
print("MLSDコマンドがサーバーでサポートされていない可能性があります。", file=sys.stderr)
finally:
if ftp and ftp.sock:
try:
ftp.quit()
print("FTP接続を閉じました。")
except all_errors as e:
print(f"警告: FTP接続の終了中にエラーが発生しました: {e}", file=sys.stderr)
print("\n--- 処理終了 ---")
これは最も確実な方法ですが、ファイルのサイズが大きい場合には非効率的で、ネットワーク帯域を消費します。
手順
- ファイルを一時的にダウンロードする。
- ダウンロードした一時ファイルのサイズをローカルで取得する。
- 一時ファイルを削除する。
利点
- 最も信頼性が高い。
- どんなFTPサーバーでも(最低限のファイル転送機能があれば)動作する。
欠点
- 一時ファイルの保存と削除の管理が必要。
- 大きなファイルでは時間がかかり、ネットワークリソースを大量に消費する。