12

What is the proper way to safely create a temporary directory in Haskell? System.IO offers ways to create temporary files, but I can't find anything that does the same for directories, neither there nor in System.Directory, System.Posix.Directory, nor System.Posix.Temp. Is there a function I'm overlooking, or do I need to write one myself? (And if so, are there any dangers to avoid, like there are with creating temporary files?)

Paul Kuliniewicz
  • 2,711
  • 18
  • 24

3 Answers3

7

For working specifically with Unix systems, the Unixutils package contains such a function:

withTemporaryDirectory :: FilePath -> (FilePath -> IO a) -> IO a

If you need it to work on both Windows and Unix systems, you'll want to use the temporary package instead. It has the same function with a slightly different type signature:

withTemporaryDirectory :: FilePath -> String -> (FilePath -> IO a) -> IO a

cimmanon
  • 67,211
  • 17
  • 165
  • 171
Don Stewart
  • 137,316
  • 36
  • 365
  • 468
  • 1
    This returns the directory where new temporary files will be created (i.e. usually "/tmp"). It doesn't actually create a temporary directory. – Travis Brown Jun 04 '10 at 23:30
  • @Travis ACK! withTemporaryDirectory was what I was looking for. – Don Stewart Jun 05 '10 at 00:05
  • This fits nicely with the usage I had in mind, since it automates cleanup of the directory when I'm done with it. – Paul Kuliniewicz Jun 05 '10 at 00:39
  • 5
    Note the [temporary](http://hackage.haskell.org/package/temporary) package, on hackage, has a host of functions along these lines. (yes, this is a year late, but this question comes up on Google searches easily) – Thomas M. DuBuisson Jun 27 '11 at 19:46
  • 2
    @ThomasM.DuBuisson you should repost this as an answer because it seems to be much more appropriate, due to being platform-agnostic. – Nikita Volkov Dec 11 '12 at 19:46
2

You could look at the Distribution.Compat.TempFile module of the Cabal source for an example. It defines createTempDirectory as follows (where c_getpid and mkPrivateDir are platform-specific):

createTempDirectory :: FilePath -> String -> IO FilePath
createTempDirectory dir template = do
  pid <- c_getpid
  findTempName pid
  where
    findTempName x = do
      let dirpath = dir </> template ++ show x
      r <- try $ mkPrivateDir dirpath
      case r of
        Right _ -> return dirpath
        Left  e | isAlreadyExistsError e -> findTempName (x+1)
                | otherwise              -> ioError e

The fact that Cabal defines this function suggests that there's not a standard way to do it.

Travis Brown
  • 138,631
  • 12
  • 375
  • 680
  • 3
    This functionality has now been factored out into the [`temporary`](http://hackage.haskell.org/package/temporary) package. – bgamari Oct 20 '14 at 23:58
  • @bgamari it seems like `temporary` package is abandoned and Cabal took this function back. Could I ask what happened? – Abastro Jul 16 '23 at 02:42
1

As suggested by @Nikita Volkov, I am posting the comment of @Thomas M. DuBuisson as a separate answer:

Use the temporary package. It provides a convenient platform-independent API for using temporary files and directories. The temporary files and directories are automatically deleted after use.

Yitz
  • 5,057
  • 24
  • 19