FilePath-0.11: Library for manipulating FilePath's in a cross platform way.ContentsIndex
System.FilePath.Version_0_11
Portabilityportable
Stabilityin-progress
Maintainerhttp://www.cs.york.ac.uk/~ndm/
Contents
Separator predicates
Path methods (environment $PATH)
Extension methods
Operations on a filepath, as a list of directories
File name manipulators
Description

A library for FilePath manipulations, designed to be cross platform. This library will select the correct type of FilePath's for the platform the code is running on at runtime. For more details see http://www.cs.york.ac.uk/~ndm/projects/libraries.php

Some short examples:

You are given a C file, you want to figure out the corresponding object (.o) file:

replaceExtension file "o"

Haskell module Main imports Test, you have the file named main:

[replaceFileName path_to_main "Test" <.> ext | ext <- ["hs","lhs"] ]

You want to download a file from the web and save it to disk:

do let file = makeValid url
   System.IO.createDirectoryIfMissing True (takeDirectory file)

You want to compile a Haskell file, but put the hi file under "interface"

takeDirectory file </> "interface" </> (takeFileName file `replaceExtension` "hi")

You want to display a filename to the user, as neatly as possible

makeRelativeToCurrentDirectory file >>= putStrLn

The examples in code format descibed by each function are used to generate tests, and should give clear semantics for the functions.

Synopsis
pathSeparator :: Char
pathSeparators :: [Char]
isPathSeparator :: Char -> Bool
searchPathSeparator :: Char
isSearchPathSeparator :: Char -> Bool
extSeparator :: Char
isExtSeparator :: Char -> Bool
splitSearchPath :: String -> [FilePath]
getSearchPath :: IO [FilePath]
splitExtension :: FilePath -> (String, String)
takeExtension :: FilePath -> String
replaceExtension :: FilePath -> String -> FilePath
dropExtension :: FilePath -> FilePath
addExtension :: FilePath -> String -> FilePath
hasExtension :: FilePath -> Bool
(<.>) :: FilePath -> String -> FilePath
splitExtensions :: FilePath -> (FilePath, String)
dropExtensions :: FilePath -> FilePath
takeExtensions :: FilePath -> String
splitFileName :: FilePath -> (String, String)
takeFileName :: FilePath -> FilePath
replaceFileName :: FilePath -> String -> FilePath
dropFileName :: FilePath -> FilePath
takeBaseName :: FilePath -> String
replaceBaseName :: FilePath -> String -> FilePath
takeDirectory :: FilePath -> FilePath
replaceDirectory :: FilePath -> String -> FilePath
isDirectory :: FilePath -> Bool
isFile :: FilePath -> Bool
asDirectory :: FilePath -> FilePath
asFile :: FilePath -> FilePath
combine :: FilePath -> FilePath -> FilePath
(</>) :: FilePath -> FilePath -> FilePath
splitPath :: FilePath -> [FilePath]
splitDirectories :: FilePath -> [FilePath]
normalise :: FilePath -> FilePath
equalFilePath :: FilePath -> FilePath -> Bool
makeRelativeToCurrentDirectory :: FilePath -> IO FilePath
makeRelative :: FilePath -> FilePath -> FilePath
isRelative :: FilePath -> Bool
isAbsolute :: FilePath -> Bool
isValid :: FilePath -> Bool
makeValid :: FilePath -> FilePath
Separator predicates
pathSeparator :: Char

The character that separates directories. In the case where more than one character is possible, pathSeparator is the 'ideal' one.

 Windows: pathSeparator == '\\'
 Posix:   pathSeparator ==  '/'
 isPathSeparator pathSeparator
pathSeparators :: [Char]

The list of all possible separators.

 Windows: pathSeparators == ['\\', '/']
 Posix:   pathSeparators == ['/']
 pathSeparator `elem` pathSeparators
isPathSeparator :: Char -> Bool

Rather than using (== pathSeparator), use this. Test if something is a path separator.

 isPathSeparator a == (a `elem` pathSeparators)
searchPathSeparator :: Char

A list of possible file separators, between the $PATH variable

 Windows: searchPathSeparator == ';'
 Posix:   searchPathSeparator == ':'
isSearchPathSeparator :: Char -> Bool

Is the character a file separator?

 isSearchPathSeparator a == (a == searchPathSeparator)
extSeparator :: Char

File extension character

 extSeparator == '.'
isExtSeparator :: Char -> Bool

Is the character an extension character?

 isExtSeparator a == (a == extSeparator)
Path methods (environment $PATH)
splitSearchPath :: String -> [FilePath]

Take a string, split it on the searchPathSeparator character.

 Windows: splitSearchPath "File1;File2;File3" == ["File1","File2","File3"]
 Posix:   splitSearchPath "File1:File2:File3" == ["File1","File2","File3"]
getSearchPath :: IO [FilePath]
Get a list of filepaths in the $PATH.
Extension methods
splitExtension :: FilePath -> (String, String)

Split on the extension. addExtension is the inverse.

 uncurry (++) (splitExtension x) == x
 uncurry addExtension (splitExtension x) == x
 splitExtension "file.txt" == ("file",".txt")
 splitExtension "file" == ("file","")
 splitExtension "file/file.txt" == ("file/file",".txt")
 splitExtension "file.txt/boris" == ("file.txt/boris","")
 splitExtension "file.txt/boris.ext" == ("file.txt/boris",".ext")
 splitExtension "file/path.txt.bob.fred" == ("file/path.txt.bob",".fred")
 splitExtension "file/path.txt/" == ("file/path.txt/","")
takeExtension :: FilePath -> String

Get the extension of a file, returns "" for no extension, .ext otherwise.

 takeExtension x == snd (splitExtension x)
 takeExtension (addExtension x "ext") == ".ext"
 takeExtension (replaceExtension x "ext") == ".ext"
replaceExtension :: FilePath -> String -> FilePath

Set the extension of a file, overwriting one if already present.

 replaceExtension "file.txt" ".bob" == "file.bob"
 replaceExtension "file.txt" "bob" == "file.bob"
 replaceExtension "file" ".bob" == "file.bob"
 replaceExtension "file.txt" "" == "file"
 replaceExtension "file.fred.bob" "txt" == "file.fred.txt"
dropExtension :: FilePath -> FilePath

Remove last extension, and any . following it.

 dropExtension x == fst (splitExtension x)
addExtension :: FilePath -> String -> FilePath

Add an extension, even if there is already one there. E.g. addExtension "foo.txt" "bat" -> "foo.txt.bat".

 addExtension "file.txt" "bib" == "file.txt.bib"
 addExtension "file." ".bib" == "file..bib"
 addExtension "file" ".bib" == "file.bib"
 Windows: addExtension "\\\\share" ".txt" == "\\\\share\\.txt"
hasExtension :: FilePath -> Bool

Does the given filename have an extension?

 null (takeExtension x) == not (hasExtension x)
(<.>) :: FilePath -> String -> FilePath
Alias to addExtension, for people who like that sort of thing.
splitExtensions :: FilePath -> (FilePath, String)

Split on all extensions

 splitExtensions "file.tar.gz" == ("file",".tar.gz")
dropExtensions :: FilePath -> FilePath

Drop all extensions

 not $ hasExtension (dropExtensions x)
takeExtensions :: FilePath -> String
Get all extensions
Operations on a filepath, as a list of directories
splitFileName :: FilePath -> (String, String)

Split a filename into directory and file. combine is the inverse.

 uncurry (++) (splitFileName x) == x
 uncurry combine (splitFileName x) == x
 splitFileName "file/bob.txt" == ("file/", "bob.txt")
 splitFileName "file/" == ("file/", "")
 splitFileName "bob" == ("", "bob")
 Posix:   splitFileName "/" == ("/","")
 Windows: splitFileName "c:" == ("c:","")
takeFileName :: FilePath -> FilePath

Get the file name.

 takeFileName "test/" == ""
 takeFileName x == snd (splitFileName x)
 takeFileName (replaceFileName x "fred") == "fred"
 takeFileName (combine x "fred") == "fred"
 isRelative (takeFileName x)
replaceFileName :: FilePath -> String -> FilePath

Set the filename.

 replaceFileName x (takeFileName x) == x
dropFileName :: FilePath -> FilePath

Drop the filename.

 dropFileName x == fst (splitFileName x)
takeBaseName :: FilePath -> String

Get the base name, without an extension or path.

 takeBaseName "file/test.txt" == "test"
 takeBaseName "dave.ext" == "dave"
replaceBaseName :: FilePath -> String -> FilePath

Set the base name.

 replaceBaseName "file/test.txt" "bob" == "file/bob.txt"
 replaceBaseName "fred" "bill" == "bill"
 replaceBaseName "/dave/fred/bob.gz.tar" "new" == "/dave/fred/new.tar"
 replaceBaseName x (takeBaseName x) == x
takeDirectory :: FilePath -> FilePath

Get the directory name, move up one level.

 Posix:    takeDirectory "/foo/bar/baz" == "/foo/bar"
 Posix:    takeDirectory "/foo/bar/baz/" == "/foo/bar/baz"
replaceDirectory :: FilePath -> String -> FilePath

Set the directory, keeping the filename the same.

 replaceDirectory x (takeDirectory x) `equalFilePath` x
isDirectory :: FilePath -> Bool

Is an item either a directory or the last character a path separator? This does not query the file system.

 isDirectory "test" == False
 isDirectory "test/" == True
isFile :: FilePath -> Bool

Is an item a file, does not query the file system.

 isDirectory x == not (isFile x)
asDirectory :: FilePath -> FilePath

Make something look like a directory

 isDirectory (asDirectory x)
 if isDirectory x then asDirectory x == x else True
 Posix:    asDirectory "test/rest" == "test/rest/"
asFile :: FilePath -> FilePath

Make something look like a file

 asFile "file/test/" == "file/test"
 not (isDirectory (asFile x)) || isDrive x
 Posix:    asFile "/" == "/"
combine :: FilePath -> FilePath -> FilePath

Combine two paths, if the second path isAbsolute, then it returns the second.

 combine (takeDirectory x) (takeFileName x) `equalFilePath` x
 Posix:   combine "/" "test" == "/test"
 Posix:   combine "home" "bob" == "home/bob"
 Windows: combine "home" "bob" == "home\\bob"
(</>) :: FilePath -> FilePath -> FilePath
A nice alias for combine.
splitPath :: FilePath -> [FilePath]

Split a path by the directory separator.

 concat (splitPath x) == x
 splitPath "test//item/" == ["test//","item/"]
 splitPath "test/item/file" == ["test/","item/","file"]
 splitPath "" == []
 Windows: splitPath "c:\\test\\path" == ["c:\\","test\\","path"]
 Posix:   splitPath "/file/test" == ["/","file/","test"]
splitDirectories :: FilePath -> [FilePath]

Just as splitPath, but don't add the trailing slashes to each element.

 splitDirectories "test/file" == ["test","file"]
 splitDirectories "/test/file" == ["/","test","file"]
 joinPath (splitDirectories (makeValid x)) `equalFilePath` makeValid x
 splitDirectories "" == []
File name manipulators
normalise :: FilePath -> FilePath

Normalise a file

  • // outside of the drive can be made blank
  • / -> pathSeparator
  • ./ -> ""
 Posix:   normalise "/file/\\test////" == "/file/\\test/"
 Posix:   normalise "/file/./test" == "/file/test"
 Posix:   normalise "/test/file/../bob/fred/" == "/test/file/../bob/fred/"
 Posix:   normalise "../bob/fred/" == "../bob/fred/"
 Posix:   normalise "./bob/fred/" == "bob/fred/"
 Windows: normalise "c:\\file/bob\\" == "C:\\file\\bob\\"
 Windows: normalise "\\\\server\\test" == "\\\\server\\test"
 Windows: normalise "c:/file" == "C:\\file"
equalFilePath :: FilePath -> FilePath -> Bool
Equality of two FilePaths. If you call System.Directory.canonicalizePath first this has a much better chance of working. Note that this doesn't follow symlinks or DOSNAM~1s.
makeRelativeToCurrentDirectory :: FilePath -> IO FilePath
makeRelative the current directory.
makeRelative :: FilePath -> FilePath -> FilePath

Contract a filename, based on a relative path.

 Posix:   makeRelative "/home/" "/home/bob/foo/bar" == "bob/foo/bar"
 Posix:   makeRelative "/fred" "bob" == "bob"
 Posix:   makeRelative "/file/test" "/file/test/fred" == "fred"
 Posix:   makeRelative "/file/test" "/file/test/fred/" == "fred/"
 Posix:   makeRelative "/fred/dave" "/fred/bill" == "../bill"
isRelative :: FilePath -> Bool

Is a path relative, or is it fixed to the root?

 Windows: isRelative "path\\test" == True
 Windows: isRelative "c:\\test" == False
 Posix:   isRelative "test/path" == True
 Posix:   isRelative "/test" == False
isAbsolute :: FilePath -> Bool
not . isRelative
 isAbsolute x == not (isRelative x)
isValid :: FilePath -> Bool

Is a FilePath valid, i.e. could you create a file like it?

 Posix:   isValid "/random_ path:*" == True
 Posix:   isValid x == True
 Windows: isValid "c:\\test" == True
 Windows: isValid "c:\\test:of_test" == False
 Windows: isValid "test*" == False
 Windows: isValid "c:\\test\\nul" == False
 Windows: isValid "c:\\test\\prn.txt" == False
 Windows: isValid "c:\\nul\\file" == False
makeValid :: FilePath -> FilePath

Take a FilePath and make it valid; does not change already valid FilePaths.

 isValid (makeValid x)
 if isValid x then makeValid x == x else True
 Windows: makeValid "c:\\test:of_test" == "c:\\test_of_test"
 Windows: makeValid "test*" == "test_"
 Windows: makeValid "c:\\test\\nul" == "c:\\test\\nul_"
 Windows: makeValid "c:\\test\\prn.txt" == "c:\\test\\prn_.txt"
 Windows: makeValid "c:\\test/prn.txt" == "c:\\test/prn_.txt"
 Windows: makeValid "c:\\nul\\file" == "c:\\nul_\\file"
Produced by Haddock version 0.8