什么是haskell复制目录的方法

时间:2011-07-24 13:24:08

标签: haskell

我发现自己在haskell中做了越来越多的脚本编写。但在某些情况下,我真的不确定如何“正确”这样做 例如以递归方式复制目录(la 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。

这是我到目前为止使用的相当天真的实现:

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

有什么方法可以做到这一点?


我根据hammar和FUZxxl的建议对此进行了更新 ......但是对于这样一个共同的任务,我仍然感觉有点笨拙!

6 个答案:

答案 0 :(得分:5)

可以使用Shelly库来执行此操作,请参阅cp_r

cp_r "sourcedir" "targetdir"

Shelly首先尝试使用原生cp -r(如果可用)。如果没有,它将回退到本机Haskell IO实现。

有关cp_r的类型语义的更多详细信息,请参阅我撰写的this post,说明如何将cp_rString和/ Text一起使用。< / p>

答案 1 :(得分:4)

我在Hackage上找不到任何能做到这一点。

您的代码对我来说非常好。一些评论:

  1. dstExists <- doesDirectoryExist dst
    

    这不考虑具有目的地名称的文件可能存在。

  2. if or [not srcExists, dstExists] then print "cannot copy"
    

    您可能希望抛出异常或返回状态,而不是直接从此函数打印。

  3. paths <- forM xs $ \name -> do
        [...]
      return ()
    

    由于您没有使用paths进行任何操作,因此您可以将其更改为

    forM_ xs $ \name -> do
      [...]
    

答案 2 :(得分:1)

MissingH包提供了递归目录遍历,您可以使用它来简化代码。

答案 3 :(得分:1)

filesystem-trees包提供了一种非常简单的实现方法:

import System.File.Tree (getDirectory, copyTo_)

copyDirectory :: FilePath -> FilePath -> IO ()
copyDirectory source target = getDirectory source >>= copyTo_ target

答案 4 :(得分:1)

我认为Path.IO copyDirRecur中的函数带有包含/排除符号链接的变体可能是一个更新且维护的解决方案。它需要将文件路径转换为Path x Dir,分别通过parseRelDirparseAbsDir实现,但是我认为拥有比FilePath更精确的日期类型值得避免。在运行时跟踪错误。

答案 5 :(得分:0)

在Haskell核心Cabal模块中,特别是Cabal包中的Distribution.Simple.Utils,还具有一些用于复制文件和目录的功能。 copyDirectoryRecursive是其中之一,并且在该模块中还有其他功能。