Copyright | (c) Andrey Mulik 2020 |
---|---|
License | BSD-style |
Maintainer | work.a.mulik@gmail.com |
Portability | non-portable (GHC extensions) |
Safe Haskell | Safe-Inferred |
Language | Haskell2010 |
Data.FilePath
provides pattern synonyms similar to System.FilePath
functions. So you don't need the filepath
package, when use sdp-io
.
Synopsis
- type FilePath = String
- isPathSep :: Char -> Bool
- isValid :: FilePath -> Bool
- isRelative :: FilePath -> Bool
- isAbsolute :: FilePath -> Bool
- makeValid :: FilePath -> FilePath
- normalise :: FilePath -> FilePath
- equalFilePath :: FilePath -> FilePath -> Bool
- makeRelative :: FilePath -> FilePath -> FilePath
- getPath :: IO [FilePath]
- pattern PathSep :: Char
- pattern (:\\) :: FilePath -> FilePath -> FilePath
- pattern (:.) :: FilePath -> String -> FilePath
- pattern (:..) :: FilePath -> [String] -> FilePath
- pattern (:/) :: FilePath -> FilePath -> FilePath
- pattern (://) :: [FilePath] -> FilePath -> FilePath
- pattern Path :: [FilePath] -> FilePath
- pattern Dirs :: [FilePath] -> FilePath
FilePath
File and directory names are values of type String
, whose precise
meaning is operating system dependent. Files can be opened, yielding a
handle which can then be used to operate on the contents of that file.
isValid :: FilePath -> Bool Source #
Is a FilePath
valid? This function checks for invalid names, invalid
characters, but doesn't check if length limits are exceeded, as these are
typically filesystem dependent.
isValid "" == False isValid "\0" == False
Posix: > isValid "/random_ path:*" == True > isValid x => not (null x)
Windows: > isValid "c:\test" == True > isValid "c:\test:of_test" == False > isValid "test*" == False > isValid "c:\test\nul" == False > isValid "c:\test\prn.txt" == False > isValid "c:\nul\file" == False > isValid "\\" == False > isValid "\\\foo" == False > isValid "\\?\D:file" == False > isValid "footbar" == False > isValid "nul .txt" == False > isValid " nul.txt" == True
isRelative :: FilePath -> Bool Source #
Is a path relative, or is it fixed to the root?
Posix: > isRelative "test/path" == True > isRelative "/test" == False > isRelative "/" == False
Windows:
isRelative "path\\test" == True isRelative "c:\\test" == False isRelative "c:test" == True isRelative "c:\\" == False isRelative "c:/" == False isRelative "c:" == True isRelative "\\\\foo" == False isRelative "\\\\?\\foo" == False isRelative "\\\\?\\UNC\\foo" == False isRelative "/foo" == True isRelative "\\foo" == True
- "A UNC name of any format [is never relative]."
- "You can't use the "\?" prefix with a relative path."
isAbsolute :: FilePath -> Bool Source #
Same as not .
.isRelative
makeValid :: FilePath -> FilePath Source #
Take a FilePath and make it vali, doesn't change already valid FilePaths:
isValid (makeValid x) == True isValid x => makeValid x == x makeValid "" == "_" makeValid "file\0name" == "file_name"
Windows: > makeValid "c:\already\valid" == "c:\already\valid" > makeValid "c:\test:of_test" == "c:\test_of_test" > makeValid "test*" == "test_" > makeValid "c:\test\nul" == "c:\test\nul_" > makeValid "c:\test\prn.txt" == "c:\test\prn_.txt" > makeValid "c:\testprn.txt" == "c:\testprn_.txt" > makeValid "c:\nul\file" == "c:\nul_\file" > makeValid "\\\foo" == "\\drive" > makeValid "\\?\D:file" == "\\?\D:\file" > makeValid "nul .txt" == "nul _.txt"
normalise :: FilePath -> FilePath Source #
Normalise a file name:
* // outside of the drive can be made blank
* / -> PathSep
* ./ -> ""
normalise "." == "."
Posix: > normalise "file\test///" == "file\test" > normalise "file.test" == "file/test" > normalise "testfile..bobfred" == "testfile..bobfred" > normalise "..bobfred" == "..bobfred" > normalise ".bobfred" == "bobfred/"
normalise "./" == "./" normalise "./." == "./" normalise "/./" == "/" normalise "/" == "/" normalise "bob/fred/." == "bob/fred/" normalise "//home" == "/home"
Windows: > normalise "c:\file/bob\" == "C:\file\bob\" > normalise "c:\" == "C:\" > normalise "C:.\" == "C:" > normalise "\\server\test" == "\\server\test" > normalise "/servertest" == "\\server\test" > normalise "c:/file" == "C:\file" > normalise "/file" == "\file" > normalise "\" == "\" > normalise "." == "\"
equalFilePath :: FilePath -> FilePath -> Bool Source #
Equality of two FilePath
s. If you call System.Directory.canonicalizePath
first this has a much better chance of working. Note that this doesn't follow
symlinks or DOSNAMEs.
x == y ==> equalFilePath x y normalise x == normalise y ==> equalFilePath x y
equalFilePath "foo" "foo/" not (equalFilePath "foo" "/foo")
Posix: > not (equalFilePath "foo" FOO)
Windows: > equalFilePath "foo" FOO > not (equalFilePath "C:" "C:/")
makeRelative :: FilePath -> FilePath -> FilePath Source #
Contract a filename, based on a relative path. Note that the resulting path
will never introduce ..
paths, as the presence of symlinks means ../b
may
not reach a/b
if it starts from a/c
. For a worked example see
this blog post.
The corresponding makeAbsolute
function can be found in System.Directory
.
makeRelative "/directory" "/directory/file.ext" == "file.ext" Valid x => makeRelative (takeDirectory x) x `equalFilePath` takeFileName x makeRelative x x == "." Valid x y => equalFilePath x y || (isRelative x && makeRelative y x == x) || equalFilePath (y </> makeRelative y x) x
Posix: > makeRelative "Home" "homebob" == "home/bob" > makeRelative "home" "homebobfoobar" == "bobfoobar" > makeRelative "/fred" "bob" == "bob" > makeRelative "filetest" "filetest/fred" == "fred" > makeRelative "filetest" "filetestfred" == "fred/" > makeRelative "somepath" "somepathabc" == "ab/c"
Windows: > makeRelative "C:\Home" "c:\home\bob" == "bob" > makeRelative "C:\Home" "c:homebob" == "bob" > makeRelative "C:\Home" "D:\Home\Bob" == "D:\Home\Bob" > makeRelative "C:\Home" "C:Home\Bob" == "C:Home\Bob" > makeRelative "Home" "home/bob" == "bob" > makeRelative "" "" == "/"
$PATH
Patterns
Drive
pattern (:\\) :: FilePath -> FilePath -> FilePath Source #
Windows: > "" :\ "file" <- "file" > "c:" :\ "file" <- "c:file" > "c:\" :\ "file" <- "c:\file" > "\\shared\" :\ "test" <- "\\shared\test" > "\\shared" :\ "" <- "\\shared" > "\\?\UNC\shared\" :\ "file" <- "\\?\UNC\shared\file" > "\\?\" :\ UNCshared\\file <- "\\?\UNCshared\file" > "\\?\d:\" :\ "file" <- "\\?\d:\file" > "" :\ "d" <- "d"
Posix: > "" :\ "test" <- "test" > "/" :\ "test" <- "/test" > "" :\ "testfile" <- "testfile" > "" :\ "file" <- "file"
Extensions
pattern (:.) :: FilePath -> String -> FilePath infixr 7 Source #
Add an extension.
"/directory/path" :. "ext" == "/directory/path.ext" "file.txt" :. "tar" == "file.txt.tar" "file." :. ".tar" == "file..tar" "file" :. ".xml" == "file.xml" "/" :. "d" == "/.d"
Windows: > "\\share" :. ".txt" == "\\share\.txt"
Split on the extension. Note that points are discarded.
("file" :. "") <- "file" ("out" :. "txt") <- "out.txt" ("/etc/pam.d/" :. "") <- "/etc/pam.d/" ("dir.d/fnya" :. "") <- "dir.d/fnya" ("dir.d/data" :. "bak") <- "dir.d/data.bak" ("/directory/path" :. "ext") <- "/directory/path.ext" ("file/path.txt.alice" :. "bob") <- "file/path.txt.alice.bob"
Note that filenames starting with a .
are handled correctly:
(".bashrc" :. "") <- ".bashrc"
pattern (:..) :: FilePath -> [String] -> FilePath infixr 7 Source #
Add an extensions.
x :.. [] = x -- forall x path :.. [ext] = path :. ext -- forall path ext
"dir/file" :.. ["fb2", "zip"] == "dir/file.fb2.zip" "dir/file" :.. ["fb2", ".zip"] == "dir/file.fb2.zip" "pacman" :.. ["pkg", "tar", "xz"] == "pacman.pkg.tar.xz"
Split on the extensions. Note that points are discarded.
("file" :.. []) <- "file" ("out" :.. ["txt"]) <- "out.txt" ("/etc/pam.d/" :.. []) <- "/etc/pam.d/" ("dir.d/fnya" :.. []) <- "dir.d/fnya" ("dir.d/data" :.. ["bak"]) <- "dir.d/data.bak" ("/directory/path" :.. ["ext"]) <- "/directory/path.ext" ("file/path." :.. ["txt", "alice", "bob"]) <- "file/path.txt.alice.bob"
This function separates the extensions and also considers the case when the file name begins with a period.
splitExtensions "file/.path.txt.alice.bob" == ("file/", ".path.txt.alice.bob") ("file/.path" :.. [txt, alice, bob]) <- "file/.path.txt.alice.bob" splitExtensions ".bashrc" == ("", ".bashrc") (".bashrc" :.. []) <- ".bashrc"
Split path
pattern (:/) :: FilePath -> FilePath -> FilePath infixr 5 Source #
Split a filename into directory and file. The first component will often end with a trailing slash.
"/directory/" :/ "file.ext" <- "/directory/file.ext" "file/" :/ "bob.txt" <- "file/bob.txt" "./" :/ "bob" <- "bob"
Posix: > "" : "" <- "/"
Windows: > "c:" :/ "" <- "c:"
Combine two paths with a path separator.
If the second path looks like an absolute path or a drive, then it returns the second.
"directory" :/ "/file.ext" == "/file.ext"
Posix: > "directory" : "file.ext" == "directoryfile.ext" > "" : "tmp" == "/tmp" > "x:" : "foo" == "x:foo" > "home" : "user" == "/user" > "home" : "user" == "homeuser"
Windows: > "directory" : "file.ext" == "/directory\file.ext" > "C:\foo" :/ "bar" == "C:\foo\bar" > "home" :/ "C:\bob" == "C:\bob" > "home" :/ "bob" == "home\bob"
"C:\\home" :/ "\\bob" == "\\bob" "home" :/ "\\bob" == "\\bob" "home" :/ "/bob" == "/bob"
"D:\\foo" :/ "C:bar" == "C:bar" "C:\\foo" :/ "C:bar" == "C:bar"
pattern (://) :: [FilePath] -> FilePath -> FilePath infixr 5 Source #
Splits/joins directories and a file name.
pattern Path :: [FilePath] -> FilePath Source #
Separates filepath into a search path - list of ancestors with trailing separators and file name (if any):
Posix: > Path ["", "home", "user", ".ghci"] <- "homeuser.ghci" > Path ["", "home", "user"] <- "homeuser" > Path ["", "home", "user"] <- "homeuser"
Windows: > Path ["C:\", "home\", "user\"] <- "C:\home\user\" > Path ["C:\", "home\", "user"] <- "C:\home\user"
Path
concatenates the file path regardless of a trailing separator.
pattern Dirs :: [FilePath] -> FilePath Source #
Separates filepath into a search path - list of ancestors without trailing separators and file name (if any):
Posix: > Dirs ["", "home", "user", ".ghci"] <- "homeuser.ghci" > Dirs ["", "home", "user"] <- "homeuser" > Dirs ["", "home", "user"] <- "home/user"
Windows: > Dirs ["C:\", "home", "user"] <- "C:\home\user\" > Dirs ["C:\","home","user"] <- "C:\home\user"
Dirs
concatenates the file path regardless of a trailing separator.