I just released version 0.1 of FileManip, a Haskell library I put together to make it easier to futz about with files in the filesystem.
There are a few different components to the package.
The
Find
module lets you search the filesystem for files, after the manner of
the Unix find
program. It provides a nice embedded language for
building filters and controlling recursion, so you can write
readable expressions like this:
find always (fileType ==? RegularFile &&? extension ==? ".hs") "myPath"
This will return a list of all Haskell source files under myPath
.
The list is built lazily, so if you have a million files in your tree,
but you only examine the first ten elements of the list, no extra work
is done.
The obvious counterparts to the Find
module in other languages would
be Perl’s File::Find
module, and Python’s os.walk
function.
The
Manip
module provides some handy functions for manipulating files. For
example, renameWith
provides procedural renaming: given a file name,
it applies a function to it, then renames the file to that name.
Here’s how you might use it to change your naming convention for C++
source files:
find always (extension ==? ".cpp") >>=
mapM_ (renameWith (replaceExtension "C"))
The modifyInPlace
and modifyWithBackup
functions edit a file in
place (the latter saves the original copy to a procedurally-renamed
backup file), so that you can more easily write sed
-like
expressions:
modifyInPlace (map toUpper) "shouting.txt"
Least interesting, but nonetheless useful, is
GlobPattern
,
a glob pattern matching module. I wrote this because Haskell doesn’t
provide a standard one, and the only other one I know of (in the
MissingH library) goes through the regexp machinery. Ew.
Online docs are published here. The source tarball is available here, at HackageDB, the Haskell package database. There’s also a Darcs repository available here:
darcs get http://darcs.serpentine.com/filemanip/
Enjoy!
I wrote a basic function, like this:
listFiles :: FilePath -> IO [FilePath]
listFiles fpath = find always (fileType ==? RegularFile &&? extension ~~? “*.(JPEG|MOV)”) fpath
and it hangs forever at 100% CPU usage…
I know I’m doing something wrong here — please help.
I’ve created find-conduit (http://hackage.haskell.org/package/find-conduit) as another way of doing efficient filesystem traversals, whose results feed into a conduit. It supports prune directory trees and makes it very easy to write new predicates.