我发现自己在Haskell做越来越多的脚本。但也有一些情况下,我真的不知道怎么做“正确的”。
例如复制一个目录递归(一拉UNIX cp -r
)。
因为我大多使用Linux和Mac OS我通常欺骗:
import System.Cmd
import System.Exit
copyDir :: FilePath -> FilePath -> IO ExitCode
copyDir src dest = system $ "cp -r " ++ src ++ " " ++ dest
但是,什么是独立于平台的方式来复制目录推荐的方法是什么? 我没有找到合适的hackage什么。
这是我相当naiv实现我使用至今:
import System.Directory
import System.FilePath((</>))
import Control.Applicative((<$>))
import Control.Exception(throw)
import Control.Monad(when,forM_)
copyDir :: FilePath -> FilePath -> IO ()
copyDir src dst = do
whenM (not <$> doesDirectoryExist src) $
throw (userError "source does not exist")
whenM (doesFileOrDirectoryExist dst) $
throw (userError "destination already exists")
createDirectory dst
content <- getDirectoryContents src
let xs = filter (`notElem` [".", ".."]) content
forM_ xs $ \name -> do
let srcPath = src </> name
let dstPath = dst </> name
isDirectory <- doesDirectoryExist srcPath
if isDirectory
then copyDir srcPath dstPath
else copyFile srcPath dstPath
where
doesFileOrDirectoryExist x = orM [doesDirectoryExist x, doesFileExist x]
orM xs = or <$> sequence xs
whenM s r = s >>= flip when r
什么真正是做到这一点有什么建议?
我用锤子和全面的建议,更新了这个。 ...但它仍然对这样一个共同的任务感到那种笨拙的我!
我找不到任何东西,这是否对Hackage。
您的代码看起来相当不错。一些评论:
dstExists <- doesDirectoryExist dst
这没有考虑到与目标文件名的文件可能存在帐户。if or [not srcExists, dstExists] then print "cannot copy"
您可能要抛出一个异常,或者返回,而不是直接从这个函数打印状态。paths <- forM xs $ \name -> do
[...]
return ()
既然你不使用paths
什么,你可以改变这
forM_ xs $ \name -> do
[...]
该MissingH
包提供递归遍历目录,您也许能够用它简化你的代码。
该filesystem-trees
包提供了一个非常简单的实现手段:
import System.File.Tree (getDirectory, copyTo_)
copyDirectory :: FilePath -> FilePath -> IO ()
copyDirectory source target = getDirectory source >>= copyTo_ target
我假定在Path.IO功能与变体copyDirRecur
包含/排除符号链接可以是较新的,并保持溶液。它需要对文件路径转换为Path x Dir
这与parseRelDir
各自parseAbsDir
实现,但我认为有一个更精确的日期类型比FilePath
是欢颜,以免难以跟踪在运行时错误。
也有在核心哈斯克尔库惊天动地的模块复制文件和目录的一些功能,特别是在Distribution.Simple.Utils包惊天动地。 copyDirectoryRecursive是其中之一,并且有接近这一个模块中的其他功能。