什么是Haskell的方式来复制一个目录

问题描述 投票:15回答:6

我发现自己在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

什么真正是做到这一点有什么建议?


我用锤子和全面的建议,更新了这个。 ...但它仍然对这样一个共同的任务感到那种笨拙的我!

haskell
6个回答
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 [...]

5
投票

这是可能的使用Shelly库为了做到这一点,看到cp_r

cp_r "sourcedir" "targetdir"

雪莉第一次尝试,如果提供给使用本地cp -r。如果不是,它回落到一个原始Haskell IO实现。

有关cp_r的类型语义进一步详情,请参阅this post由我写来描述如何与cp_r和或String使用Text

谢莉是不是独立的平台,因为它依赖于Unix包,这是不是在Windows下支持。


1
投票

MissingH包提供递归遍历目录,您也许能够用它简化你的代码。


1
投票

filesystem-trees包提供了一个非常简单的实现手段:

import System.File.Tree (getDirectory, copyTo_)

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

1
投票

我假定在Path.IO功能与变体copyDirRecur包含/排除符号链接可以是较新的,并保持溶液。它需要对文件路径转换为Path x Dir这与parseRelDir各自parseAbsDir实现,但我认为有一个更精确的日期类型比FilePath是欢颜,以免难以跟踪在运行时错误。


0
投票

也有在核心哈斯克尔库惊天动地的模块复制文件和目录的一些功能,特别是在Distribution.Simple.Utils包惊天动地。 copyDirectoryRecursive是其中之一,并且有接近这一个模块中的其他功能。

© www.soinside.com 2019 - 2024. All rights reserved.