HaskellでFTPクライアント
Posted 10月 12th, 2010 by hippos
in
コード片としてPerl/Net::FTPをよく利用していますが、前回に続きこの部分もNetwork.FTP.Clientを使ってHaskellで書いてみました。ダウンロード対象を記述した以下の形式のファイル
# 行頭# はコメント行
remote_file_name,local_file_name
:
:を読み込んでサーバからダウンロードしリネームして保存するだけのサンプルです。
type RemoteFileName = FilePath
type LocalFileNmae = FilePath
splt :: String -> (RemoteFileName,LocalFileNmae)
splt xs = (r,l)
where
r = takeWhile (\x -> x /= ',') xs
l = tail $ dropWhile(\x -> x /= ',') xs
dlst :: String -> IO [(RemoteFileName,LocalFileNmae)]
dlst dl = do cs <- readFile dl
let fl = map splt $ rme $ lines cs
return fl
where
rme xs = filter(\x -> isCmnt x) $ filter(\x -> length x > 0) xs
isCmnt (x:_) = if x == '#' then False else Trueで、[(リモートファイル名,ローカルファイル名)]のリストを作成し、後はリストを順にダウンロードします。
dld :: FTPConnection -> (RemoteFileName,LocalFileNmae) -> IO ()
dld c (r,l) = do
result <- getbinary c r
oh <- openBinaryFile l WriteMode
hPutStr oh (fst result)
hClose(oh)
main = do arg <- getArgs
conn <- easyConnectFTP "ftp.server.com"
login conn "account" (Just "password") Nothing
cwd conn "path/to/file"
l <- dlst (head arg)
mapM (\x -> dld conn x) l
quit conn
簡単に実装できましたが、perlのNet::FTPの
$ftp->get($remote,$local) or die "…";のようにリネームしながらのダウンロードができないのは不便かな?getbinaryの結果を書き出したい名前で改めてwriteする必要がありました。ダウンロードしたファイルの中身を操作したいときは便利ですが、単に名前を変えてダウンロードしたいときはちょっと手間。リネームしないのならdownloadbinaryで一気にダウンロードできます。
後、getlinesもPrelude.lineと同様改行文字は取り除かれてしまうようなので行末処理は自前になります。インタプリタ上でIO ([String], FTPResult)を評価すると(改行も含んだ)全テキストが
Prelude Network.FTP.Client> getlines h "sample.pl"
(["#!/usr/bin/perl\n#\nuse strict;\n\nprint \"hello world\\n\";\n"],
(226,["File send OK."]))のように取得されれてしまうのでデバグにはずいぶんと悩みました。これが遅延評価というやつでしょうか?headとかtakeとかmapで行単位で評価すれば分割して取れるようです。(どうやって確認したらいいのかわかりませんが...)なので、
dld c (r,l) = do result <- getlines c r
oh <- openFile l WriteMode
hPutStr oh (concat $ map(\x -> x++['\n']) $ (fst rs))
hClose ohこんな実装で行末変換しました。このあたりはちょっと実用に向かないかも....
この記事のトラックバックURL:
http://hippos-lab.com/blog/trackback/379


最近のコメント
14 weeks 4 days ago
49 weeks 2 days ago
1年 14 weeks ago
1年 14 weeks ago
1年 31 weeks ago
1年 31 weeks ago
1年 31 weeks ago
1年 43 weeks ago
1年 43 weeks ago
2 years 23 weeks ago