|
- {-# LANGUAGE ForeignFunctionInterface #-}
- {-# LANGUAGE OverloadedStrings #-}
- {-# LANGUAGE TupleSections #-}
- {-# LANGUAGE ViewPatterns #-}
-
- {-# OPTIONS_GHC -Wall #-}
- import Control.Applicative
- import Control.Monad
- import System.Directory
- import System.FilePath ((</>))
- import System.Posix.ByteString.FilePath
- import System.Posix.Directory.ByteString as PosixBS
- import System.Posix.Directory.Traversals
- import qualified System.Posix.FilePath as PosixBS
- import System.Posix.Files.ByteString
-
- import Control.Exception
- import qualified Data.ByteString.Char8 as BS
-
- import System.Environment (getArgs, withArgs)
- import System.IO.Error
- import System.IO.Unsafe
- import System.Process (system)
- import Criterion.Main
-
-
- -- | Based on code from 'Real World Haskell', at
- -- http://book.realworldhaskell.org/read/io-case-study-a-library-for-searching-the-filesystem.html#id620419
- listFilesRecursive :: FilePath -> IO [FilePath]
- listFilesRecursive topdir = do
- names <- System.Directory.getDirectoryContents topdir
- let properNames = filter (`notElem` [".", ".."]) names
- paths <- forM properNames $ \name -> do
- let path = topdir </> name
- isDir <- doesDirectoryExist path
- if isDir
- then listFilesRecursive path
- else return [path]
- return (topdir : concat paths)
-
- ----------------------------------------------------------
-
- getDirectoryContentsBS :: RawFilePath -> IO [RawFilePath]
- getDirectoryContentsBS path =
- modifyIOError ((`ioeSetFileName` (BS.unpack path)) .
- (`ioeSetLocation` "getDirectoryContentsBS")) $ do
- bracket
- (PosixBS.openDirStream path)
- PosixBS.closeDirStream
- loop
- where
- loop dirp = do
- e <- PosixBS.readDirStream dirp
- if BS.null e then return [] else do
- es <- loop dirp
- return (e:es)
-
-
- -- | similar to 'listFilesRecursive, but uses RawFilePaths
- listFilesRecursiveBS :: RawFilePath -> IO [RawFilePath]
- listFilesRecursiveBS topdir = do
- names <- getDirectoryContentsBS topdir
- let properNames = filter (`notElem` [".", ".."]) names
- paths <- forM properNames $ \name -> unsafeInterleaveIO $ do
- let path = PosixBS.combine topdir name
- isDir <- isDirectory <$> getFileStatus path
- if isDir
- then listFilesRecursiveBS path
- else return [path]
- return (topdir : concat paths)
- ----------------------------------------------------------
-
-
- benchTraverse :: RawFilePath -> IO ()
- benchTraverse = traverseDirectory (\() p -> BS.putStrLn p) ()
-
- main :: IO ()
- main = do
- args <- getArgs
- let (d,otherArgs) = case args of
- [] -> ("/usr/local",[])
- x:xs -> (x,xs)
- withArgs otherArgs $ defaultMain
- [ bench "traverse (FilePath)" $ nfIO $ listFilesRecursive d >>= mapM_ putStrLn
- , bench "traverse (RawFilePath)" $ nfIO $ listFilesRecursiveBS (BS.pack d) >>= mapM_ BS.putStrLn
- , bench "allDirectoryContents" $ nfIO $ allDirectoryContents (BS.pack d) >>= mapM_ BS.putStrLn
- , bench "allDirectoryContents'" $ nfIO $ allDirectoryContents' (BS.pack d) >>= mapM_ BS.putStrLn
- , bench "traverseDirectory" $ nfIO $ benchTraverse (BS.pack d)
- , bench "unix find" $ nfIO $ void $ system ("find " ++ d)
- ]
|