Net::FTP - FTPを使ったファイル転送
Net::FTPを使用すると、FTPでファイルのダウンロード・アップロードができます。
IT関連の仕事ではサーバにアクセスしてファイルをダウンロード・アップロードすることが頻繁にあります。FFFTPなどのFTPのクライアントのソフトウェアなどを使用してこれを行うのは非常に手間がかかります。できれば自動化したいと思うことでしょう。
PerlにはFTPを行うためのクライアントアプリケーションを作成するためのNet::FTPというモジュールが標準で添付されています。Net::FTPを使えばファイルのダウンロード・アップロード作業は自動化され業務の効率化を図ることができます。
FTPとは
FTPはファイルを転送するためのプロトコルです。FTPを使用すればファイルのアップロードやダウンロードを行うことができます。FTPのもうすこし解説は「第56回FTP(1) 概要(3分間Networking」がわかりやすいと思います。
ここでは詳しい解説は行わずにFTPサーバに接続してファイルをダウンロードする手順を簡単に解説します。FTPサーバに接続してファイルをダウンロードするには次の3つ手順を踏みます。
- ホスト名(あるいはIPアドレス)を指定してFTPサーバに接続する。
- ユーザ名とパスワードを入力してログインする
- FTPコマンドを使用してファイルをダウンロードする
- 接続を終了する
ファイルをダウンロードする簡単なサンプル
実際にファイルをダウンロードする簡単なサンプルを書いてみます。
# モジュールの読み込み use Net::FTP; # FTPサーバへの接続(ホスト名でもIPアドレスでもOK) my $ftp = Net::FTP->new('somehost'); # ユーザ名とパスワードを指定してログイン $ftp->login('user', 'password'); # getというファイルを取得するコマンドを使ってファイルをダウンロード $ftp->get('/dir/somefile'); # 接続を終了する $ftp->quit;
newメソッドに接続先を指定するとFTPサーバに接続することができます。また戻り値にはオブジェクトが返却されこれを利用してログインしたりFTPコマンドを発行したりします。
loginメソッドにユーザ名とパスワードを指定するとFTPサーバにログインすることができます。ログインというのは簡単にいうとサーバによってFTPコマンドを実行する許可が与えられた状態のことをいいます。
getというメソッドを使用するとファイルをダウンロードすることができます。ファイルはカレントディレクトリにダウンロードされます。ファイル名はディレクトリ名を含まない末尾の名前(このサンプルではsomefile)になります。
よく使用するメソッド
よく使用するメソッドについて紹介します。
new
Net::FTPオブジェクトを作成してFTPサーバに接続します。
$ftp = Net::FTP->new($host);
引数にはホスト名かIPアドレスを指定することができます。また第2引数以降はオプションを指定することができます。オプションはハッシュのリファレンスで指定します。よく使用するオプションとしてはタイムアウトの秒数を設定するためのTimeoutなどがあります。デフォルトのタイムアウトの秒数は120秒です。
$ftp = Net::FTP->new($host, Timeout => 180)
login
ユーザ名とパスワードを指定してログインします。
$ftp->login($user, $password)
匿名でFTPサーバに接続する場合はユーザ名に「anonymous」を指定します。
$ftp->login('anonymous')
cwd
接続先のカレントディレクトリを変更します。
$ftp->cwd($dir)
FTPはステートフルなプロトコルで接続先のディレクトリを変更することができます。ファイルをダウンロードする場合はカレントディレクトリを変更してからファイル名だけを指定するのが一般的かもしれません。
$ftp->cwd('dir') # カレントディレクトリ変更 $ftp->get('somefile') # ファイルのダウンロード
get
ファイルをダウンロードするにはgetを使用します。
$ftp->get($file)
第2引数にファイル名を指定すると名前を変えてダウンロードを行うことができます。
$ftp->get($file, $renamed_file)
put
ファイルをアップロードするにはputを使用します。
$ftp->put($file$)
第2引数にファイル名を指定すると名前を変えてアップロードを行うことができます。
$ftp->put($file, $renamed_file)
binary
ファイルの転送モードをバイナリモードに変更します。
$ftp->binary
FTPにはファイルの転送モードという考え方があります。転送モードにはバイナリモードとアスキーモードの2種類があります。
バイナリモードを指定するとファイルを転送するときに何の変換も行いません。画像ファイルや動画ファイルなどを転送する場合はかならずバイナリモードで転送する必要があります。
ascii
ファイルの転送モードをアスキーモードに変更します。
$ftp->ascii
アスキーモードを指定すると改行コードの自動変換を行ってくれます。たとえばWindowsのデフォルトの改行コードは\r\nです。Unixのデフォルトの改行コードは\nです。Windowsのメモ帳などで作成したファイルをそのままUnixに転送すると正しく表示することができません。アスキーモードで転送するとこの変換を自動で行ってくれます。
ls
ファイル名の一覧を取得します。
@files = $ftp->ls($dir)
ディレクトリ名を省略した場合は接続先のカレントディレクトリに含まれるファイルの一覧を取得します。
ファイルの存在を確認するには、lsメソッドを使って、ファイルの一覧を取得して、確認します。
dir
ファイル名の一覧を詳細な情報を含めて取得します。
@file_infos = $ftp->dir($dir)
dirコマンドはOS依存です。そのOSで「ls -l」を実行した出力結果が得られます。たとえば私の現在使用しているFedora7の場合は次のような出力になります。
-rw-r--r-- 1 someuser somegroup 6618 Aug 8 17:22 button.html -rwxr-xr-x 3 someuser somegroup 512 Apr 1 2009 a.pl -rwx------ 1 someuser somegroup 77 Apr 1 2009 mm.txt
rmdir
ディレクトリを削除します。
# ディレクトリの削除 $ftp->rmdir($dir)
mkdir
ディレクトリを作成します。第二引数が真であれば、再帰的にディレクトリを作成します。
# ディレクトリを作成 $ftp->mkdir($dir) # 再帰的にディレクトリを作成 $ftp->mkdir($dir, $is_recurse)
quit
FTPサーバーとの接続を閉じます。
$ftp->quit;
ときどき使用するメソッド
ときどき使用するメソッドです。
メソッド名 | 機能 |
pwd | 接続先のカレントディレクトリの取得 |
rename | ファイル名の変更 |
mkdir | ディレクトリの作成 |
rmdir | ディレクトリの削除 |
size | ファイルサイズの取得 |
すべてのメソッドの一覧
メソッドのすべての一覧はNet::FTPのマニュアルを参照してください。
Net::FTPのエラー処理
実は最初のサンプルではNet::FTPの使い方を簡潔に説明するためにエラー処理を省いていました。Net::FTPはコマンドなどが失敗した場合に例外を投げてくれないので自前でエラー処理を行う必要があります。最初のサンプルにエラー処理を加えると次のようになります。
# FTPサーバへの接続 my $ftp = Net::FTP->new('somehost') or die "Cannot connect to '$host': $!"; # ログイン $ftp->login('user', 'password') or die "Cannot login '$host:$user:$password': " . $ftp->message; # ダウンロード $ftp->get('/dir/somefile'); or die "FTP command fail: " . $ftp->message; $ftp->quit;
エラー処理はなぜ行う必要があるのでしょうか?それはFTPサーバは外部にあるため確実に成功する保障はどこにもないからです。ネットワークのエラーやサーバのダウンなどで接続できないというときのことについて考える必要があります。
またホスト名が間違っていた場合は接続に失敗します。このような場合に残りの処理を続けたとしても意味がありません。わかりやすいエラーメッセージを表示してプログラムは止まるべきです。
ではNet::FTPのエラー処理について簡単に解説します。
[A]接続のエラー処理
newメソッドでFTPサーバへの接続に失敗した場合は戻り値はundefになりますのでor dieをしてプログラムを終了させます。OSのエラーメッセージである$!を含めておきましょう。
my $ftp = Net::FTP->new('somehost') or die "Cannot connect to '$host': $!";
[B]それ以外のエラー処理
接続した後にエラーが発生した場合は$ftp->messageでエラーの内容を取得することができます。このエラーメッセージをエラーメッセージに含めるようにします。
# ログイン $ftp->login('user', 'password') or die "Cannot login '$host:$user:$password: '" . $ftp->message; # ダウンロード $ftp->get('/dir/somefile'); or die "FTP command fail: " . $ftp->message;
Net::FTPの実行できるサンプル
ユーザとパスワードを指定するFTPサーバにはサンプルでは接続することができません。パスワードを指定しないでもよい匿名サーバからファイルをダウンロードしてみます。CPANのミラーサイトからCPANのトップページ(index.html)をダウンロードするサンプルです。
use strict; use warnings; use Net::FTP; my $host = 'ftp.u-aizu.ac.jp'; my $user = 'anonymous'; my $ftp = Net::FTP->new($host) or die "Cannot connect to '$host': $!"; $ftp->login($user) or die "Cannot login '$host:$user':" . $ftp->message; $ftp->cwd('/pub/CPAN') or die "FTP command fail: " . $ftp->message; $ftp->get('index.html') or die "FTP command fail: " . $ftp->message; $ftp->quit;
FTPSによる接続 - FTP over SSL/TLS
Net::FTPによるFTPSによる接続方法について解説します。FTPSは、SSL/TSL上でFTP接続するプロトコルです。SSH上でファイル転送を行うSFTPとは、異なるものなので注意してください。
ここでは、FTPのポート番号(標準で21)でFTP接続した後に、AUTHコマンドでSSL接続要求を行う「明示的なTSL/SSL暗号化」を行う方法について解説します。
Net::FTPは、IO::Socket::SSLがインストールされている場合、FTPSを使って通信を行うことができます。IO::Socket::SSLのバージョンが古い場合は、アップグレードしてください。
「明示的なTSL/SSL暗号化」を行うには、newメソッドで接続した直後に、starttlsメソッドを呼び出すだけです。上記のサンプルを「明示的なTSL/SSL暗号化」で書き直してみましょう。
use strict; use warnings; use Net::FTP; my $host = 'ftp.u-aizu.ac.jp'; my $user = 'anonymous'; my $ftp = Net::FTP->new($host) or die "Cannot connect to '$host': $!"; # 明示的なTSL/SSL暗号化を開始 $ftp->starttls() or die "Can't upgrade start TLS:"; $ftp->login($user) or die "Cannot login '$host:$user':" . $ftp->message; $ftp->cwd('/pub/CPAN') or die "FTP command fail: " . $ftp->message; $ftp->get('index.html') or die "FTP command fail: " . $ftp->message; $ftp->quit;