You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

91 lines
3.2 KiB

  1. {-# LANGUAGE ForeignFunctionInterface #-}
  2. {-# LANGUAGE OverloadedStrings #-}
  3. {-# LANGUAGE TupleSections #-}
  4. {-# LANGUAGE ViewPatterns #-}
  5. {-# OPTIONS_GHC -Wall #-}
  6. import Control.Applicative
  7. import Control.Monad
  8. import System.Directory
  9. import System.FilePath ((</>))
  10. import System.Posix.ByteString.FilePath
  11. import System.Posix.Directory.ByteString as PosixBS
  12. import System.Posix.Directory.Traversals
  13. import qualified System.Posix.FilePath as PosixBS
  14. import System.Posix.Files.ByteString
  15. import Control.Exception
  16. import qualified Data.ByteString.Char8 as BS
  17. import System.Environment (getArgs, withArgs)
  18. import System.IO.Error
  19. import System.IO.Unsafe
  20. import System.Process (system)
  21. import Criterion.Main
  22. -- | Based on code from 'Real World Haskell', at
  23. -- http://book.realworldhaskell.org/read/io-case-study-a-library-for-searching-the-filesystem.html#id620419
  24. listFilesRecursive :: FilePath -> IO [FilePath]
  25. listFilesRecursive topdir = do
  26. names <- System.Directory.getDirectoryContents topdir
  27. let properNames = filter (`notElem` [".", ".."]) names
  28. paths <- forM properNames $ \name -> do
  29. let path = topdir </> name
  30. isDir <- doesDirectoryExist path
  31. if isDir
  32. then listFilesRecursive path
  33. else return [path]
  34. return (topdir : concat paths)
  35. ----------------------------------------------------------
  36. getDirectoryContentsBS :: RawFilePath -> IO [RawFilePath]
  37. getDirectoryContentsBS path =
  38. modifyIOError ((`ioeSetFileName` (BS.unpack path)) .
  39. (`ioeSetLocation` "getDirectoryContentsBS")) $ do
  40. bracket
  41. (PosixBS.openDirStream path)
  42. PosixBS.closeDirStream
  43. loop
  44. where
  45. loop dirp = do
  46. e <- PosixBS.readDirStream dirp
  47. if BS.null e then return [] else do
  48. es <- loop dirp
  49. return (e:es)
  50. -- | similar to 'listFilesRecursive, but uses RawFilePaths
  51. listFilesRecursiveBS :: RawFilePath -> IO [RawFilePath]
  52. listFilesRecursiveBS topdir = do
  53. names <- getDirectoryContentsBS topdir
  54. let properNames = filter (`notElem` [".", ".."]) names
  55. paths <- forM properNames $ \name -> unsafeInterleaveIO $ do
  56. let path = PosixBS.combine topdir name
  57. isDir <- isDirectory <$> getFileStatus path
  58. if isDir
  59. then listFilesRecursiveBS path
  60. else return [path]
  61. return (topdir : concat paths)
  62. ----------------------------------------------------------
  63. benchTraverse :: RawFilePath -> IO ()
  64. benchTraverse = traverseDirectory (\() p -> BS.putStrLn p) ()
  65. main :: IO ()
  66. main = do
  67. args <- getArgs
  68. let (d,otherArgs) = case args of
  69. [] -> ("/usr/local",[])
  70. x:xs -> (x,xs)
  71. withArgs otherArgs $ defaultMain
  72. [ bench "traverse (FilePath)" $ nfIO $ listFilesRecursive d >>= mapM_ putStrLn
  73. , bench "traverse (RawFilePath)" $ nfIO $ listFilesRecursiveBS (BS.pack d) >>= mapM_ BS.putStrLn
  74. , bench "allDirectoryContents" $ nfIO $ allDirectoryContents (BS.pack d) >>= mapM_ BS.putStrLn
  75. , bench "allDirectoryContents'" $ nfIO $ allDirectoryContents' (BS.pack d) >>= mapM_ BS.putStrLn
  76. , bench "traverseDirectory" $ nfIO $ benchTraverse (BS.pack d)
  77. , bench "unix find" $ nfIO $ void $ system ("find " ++ d)
  78. ]