System.IO
Standard File Handlers:
- stdin
- stdout
- stderr
IOMode
- ReadMode
- WriteMode
- AppendMode
- ReadWriteMode
> :t putStrLn
putStrLn :: String -> IO ()
>
-- Bind operator
--
> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
>
-- Reverse bind operator
--
--
> :t (=<<)
(=<<) :: Monad m => (a -> m b) -> m a -> m b
>
> :t readFile "/etc/lsb-release"
readFile "/etc/lsb-release" :: IO String
>
> readFile "/etc/lsb-release"
"DISTRIB_ID=Ubuntu\nDISTRIB_RELEASE=15.04 ..."
> readFile "/etc/lsb-release" >>= putStrLn
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=15.04
DISTRIB_CODENAME=vivid
DISTRIB_DESCRIPTION="Ubuntu 15.04"
> putStrLn =<< readFile "/etc/lsb-release"
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=15.04
DISTRIB_CODENAME=vivid
DISTRIB_DESCRIPTION="Ubuntu 15.04"
-- This code must be loaded from a file:
--
showFile fileName = do
content <- readFile fileName
putStrLn content
-- This code can be pasted in the repl.
--
> let showFile3 fileName = do { content <- readFile fileName ; putStrLn content }
>
> :t showFile3
showFile3 :: FilePath -> IO ()
> showFile "/etc/lsb-release"
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=15.04
DISTRIB_CODENAME=vivid
DISTRIB_DESCRIPTION="Ubuntu 15.04"
-- Dessugarized.
--
> let showFile2 fileName = readFile fileName >>= \content -> putStrLn content
>
> showFile2 "/etc/lsb-release"
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=15.04
DISTRIB_CODENAME=vivid
DISTRIB_DESCRIPTION="Ubuntu 15.04"
> import qualified System.IO as SIO
>
-- Type tab to list the module
--
> SIO.
>
Display all 106 possibilities? (y or n)
SIO.AbsoluteSeek SIO.hPutChar
SIO.AppendMode SIO.hPutStr
SIO.BlockBuffering SIO.hPutStrLn
SIO.BufferMode SIO.hReady
SIO.CRLF SIO.hSeek
> :t SIO.readFile
SIO.readFile :: FilePath -> IO String
>
-- File handler / File descriptor (Unix File descriptor)
--
> let fd = SIO.openFile "/etc/lsb-release" SIO.ReadMode
> :t SIO.openFile
SIO.openFile :: FilePath -> SIO.IOMode -> IO SIO.Handle
>
> fd
{handle: /etc/lsb-release}
> :t fd
fd :: IO SIO.Handle
>
-- Return a line from file descritor
--
> :t SIO.hGetLine
SIO.hGetLine :: SIO.Handle -> IO String
>
> fd >>= SIO.hGetLine
"DISTRIB_ID=Ubuntu"
> fd >>= SIO.hGetLine
"DISTRIB_ID=Ubuntu"
>
import qualified System.IO as SIO
readThreeLines fileName = do
fd <- SIO.openFile fileName SIO.ReadMode
line1 <- SIO.hGetLine fd
line2 <- SIO.hGetLine fd
line3 <- SIO.hGetLine fd
SIO.hClose fd
return [line1, line2, line3]
-- --------------------------------
- ---------------------------------
> :paste
> readThreeLines "/etc/lsb-release"
["DISTRIB_ID=Ubuntu","DISTRIB_RELEASE=15.04","DISTRIB_CODENAME=vivid"]
>
> :t readThreeLines "/etc/lsb-release"
readThreeLines "/etc/lsb-release" :: IO [String]
import qualified System.IO as SIO
> let fd = SIO.openFile "/etc/lsb-release" SIO.ReadMode
> :t fd
fd :: IO SIO.Handle
>
> fd >>= SIO.hGetContents
"DISTRIB_ID=Ubuntu\nDISTRIB_RELEASE=15.04\nDISTRIB_CODENAME ... ... "
>
> fd >>= SIO.hGetContents >>= putStrLn
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=15.04
DISTRIB_CODENAME=vivid
DISTRIB_DESCRIPTION="Ubuntu 15.04"
let readLine fd = SIO.hGetLine fd >>= \line -> return (line, fd)
> :t readLine
readLine :: SIO.Handle -> IO (String, SIO.Handle)
>
> fd >>= readLine
("DISTRIB_ID=Ubuntu",{handle: /etc/lsb-release})
>
> fd >>= readLine
("DISTRIB_ID=Ubuntu",{handle: /etc/lsb-release})
>
> let readTwoLines fd = readLine fd >>= \(line1, fd) -> readLine fd >>= \(line2, fd) -> return ([line1, line2], fd)
> fd >>= readTwoLines
(["DISTRIB_ID=Ubuntu","DISTRIB_RELEASE=15.04"],{handle: /etc/lsb-release})
>
import qualified System.IO as SIO
fdtest = SIO.openFile "/etc/lsb-release" SIO.ReadMode
readLineState :: SIO.Handle -> IO (String, SIO.Handle)
readLineState fd = do
line <- SIO.hGetLine fd
return (line, fd)
readLinesAux :: SIO.Handle -> [String] -> IO [String]
readLinesAux fd lines = do
(lin, fdnext) <- readLineState fd
isEOF <- SIO.hIsEOF fdnext
if isEOF
then return (reverse lines)
else readLinesAux fdnext (lin:lines)
readLines :: SIO.Handle -> IO [String]
readLines fd = readLinesAux fd []
readLinesFromFile :: String -> IO [String]
readLinesFromFile fileName = do
handle <- SIO.openFile fileName SIO.ReadMode
lines <- readLines handle
SIO.hClose handle
return lines
makeReader :: (SIO.Handle -> IO out) -> (SIO.Handle -> IO (out, SIO.Handle))
makeReader reader fd = do
out <- reader fd
return (out, fd)
applyFileReaderAux :: (SIO.Handle -> IO (out, SIO.Handle)) -> SIO.Handle -> [out] -> IO [out]
applyFileReaderAux fileReader fd acc = do
(output, fdnext) <- fileReader fd
isEOF <- SIO.hIsEOF fdnext
if isEOF
then return (reverse acc)
else applyFileReaderAux fileReader fdnext (output:acc)
applyFileReader :: (SIO.Handle -> IO (out, SIO.Handle)) -> SIO.Handle -> IO [out]
applyFileReader fileReader fd = applyFileReaderAux fileReader fd []
Repl tests:
> :t fdtest
fdtest :: IO SIO.Handle
>
> :t readLineState
readLineState :: SIO.Handle -> IO (String, SIO.Handle)
>
> fdtest >>= readLineState
("DISTRIB_ID=Ubuntu",{handle: /etc/lsb-release})
>
> readLineState =<< fdtest
("DISTRIB_ID=Ubuntu",{handle: /etc/lsb-release})
>
> fdtest >>= \fd -> readLinesAux fd []
["DISTRIB_ID=Ubuntu","DISTRIB_RELEASE=15.04","DISTRIB_CODENAME=vivid"]
>
> :t fdtest >>= \fd -> readLinesAux fd []
fdtest >>= \fd -> readLinesAux fd [] :: IO [String]
>
> fdtest >>= readLines
["DISTRIB_ID=Ubuntu","DISTRIB_RELEASE=15.04","DISTRIB_CODENAME=vivid"]
>
> readLinesFromFile "/etc/lsb-release"
["DISTRIB_ID=Ubuntu","DISTRIB_RELEASE=15.04","DISTRIB_CODENAME=vivid"]
>
> :t SIO.withFile
SIO.withFile
:: FilePath -> SIO.IOMode -> (SIO.Handle -> IO r) -> IO r
>
> SIO.withFile "/etc/lsb-release" SIO.ReadMode readLines
["DISTRIB_ID=Ubuntu","DISTRIB_RELEASE=15.04","DISTRIB_CODENAME=vivid"]
>
> :t SIO.withFile "/etc/lsb-release" SIO.ReadMode readLines
SIO.withFile "/etc/lsb-release" SIO.ReadMode readLines
:: IO [String]
-- ------------------------
>
> fd <- SIO.openFile "/etc/lsb-release" SIO.ReadMode
> :t fd
fd :: SIO.Handle
>
> fd
{handle: /etc/lsb-release}
>
> :t readLineState
readLineState :: SIO.Handle -> IO (String, SIO.Handle)
> applyFileReaderAux readLineState fd []
["DISTRIB_ID=Ubuntu","DISTRIB_RELEASE=15.04","DISTRIB_CODENAME=vivid"]
>
> let charReader = makeReader SIO.hGetChar
> :t charReader
charReader :: SIO.Handle -> IO (Char, SIO.Handle)
>
> applyFileReader charReader fd
"DISTRIB_ID=Ubuntu\nDISTRIB_RELEASE=15.04\nDISTRIB_CODENAME= ..."
>
> fd <- SIO.openFile "/etc/lsb-release" SIO.ReadMode
> applyFileReader (makeReader SIO.hGetLine) fd
["DISTRIB_ID=Ubuntu","DISTRIB_RELEASE=15.04","DISTRIB_CODENAME=vivid"]
>
> applyFileReader (makeReader SIO.hGetLine) fd
*** Exception: /etc/lsb-release: hGetLine: end of file
>
Miscellaneous information about the system environment.
> import qualified System.Environment as E
>
-- returns a list of the program's command line arguments
-- (not including the program name).
--
> E.getArgs
[]
> :t E.getArgs
E.getArgs :: IO [String]
>
-- Computation getProgName returns the name of the program as it was invoked.
--
> :t E.getProgName
E.getProgName :: IO String
>
> E.getProgName
"<interactive>"
>
-- Returns the absolute pathname of the current executable.
-- Note that for scripts and interactive sessions, this is
-- the path to the interpreter (e.g. ghci.)
> :t E.getExecutablePath
E.getExecutablePath :: IO FilePath
>
> E.getExecutablePath
"/usr/lib/ghc/lib/ghc"
>
> path <- E.getExecutablePath
> :t path
path :: FilePath
> path
"/usr/lib/ghc/lib/ghc"
>
-- Computation getEnv var returns the value of the environment
-- variable var. For the inverse, POSIX users can use putEnv.
--
--
> :t E.getEnv
E.getEnv :: String -> IO String
>
> E.getEnv "HOME"
"/home/tux"
>
> E.getEnv "PATH"
"/home/tux/.cask/bin:/opt/bin:/home/tux/.opam/4.02.1/bin:/home/tux/bin ..."
> E.getEnv "DONTEXISTS"
*** Exception: DONTEXISTS: getEnv: does not exist (no environment variable)
>
-- Return the value of the environment variable var,
-- or Nothing if there is no such value.
--
> :t E.lookupEnv
E.lookupEnv :: String -> IO (Maybe String)
>
> E.lookupEnv "JDK_HOME"
Just "/opt/java"
>
> E.lookupEnv "JDK_HOMEasdasd"
Nothing
>
-- getEnvironment retrieves the entire environment as a list of (key,value) pairs.
> :t E.getEnvironment
E.getEnvironment :: IO [(String, String)]
>
> E.getEnvironment >>= \lst -> return (take 10 lst)
[("USER","tux"),("LANGUAGE","en_US"),("LC_TIME","pt_BR.UTF-8"),("COMP_WORDBREAKS"," \t\n\"'><;|&(:"),("XDG_SEAT","seat0"),("SSH_AGENT_PID","15614"),("XDG_SESSION_TYPE","x11"),("SHLVL","1"),("HOME","/home/tux"),("QT4_IM_MODULE","xim")]
>
> :t mapM_
mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
>
> :t E.getEnvironment >>= \rows -> mapM_ (\row -> putStrLn (show row)) rows
E.getEnvironment >>= \rows -> mapM_ (\row -> putStrLn (show row)) rows
:: IO ()
>
> E.getEnvironment >>= \rows -> mapM_ (\row -> putStrLn (show row)) rows
("USER","tux")
("LANGUAGE","en_US")
("LC_TIME","pt_BR.UTF-8")
("XDG_SEAT","seat0")
("SSH_AGENT_PID","15614")
("XDG_SESSION_TYPE","x11")
("SHLVL","1")
...
> import qualified System.Directory as D
>
-- createDirectory dir creates a new directory dir which is initially
-- empty, or as near to empty as the operating system allows.
> D.createDirectory "/tmp/testdir"
> D.createDirectory "/tmp/testdir"
*** Exception: /tmp/testdir: createDirectory: already exists (File exists)
>
{-
createDirectoryIfMissing Source
:: Bool Create its parents too?
-> FilePath The path to the directory you want to make
-> IO ()
-}
> D.createDirectoryIfMissing True "/tmp/tree1/1/2/3/4"
>
> D.createDirectoryIfMissing True "/tmp/tree1/1/2/3/4"
>
> D.createDirectoryIfMissing True "/tree1/1/2/3/4"
*** Exception: /tree1: createDirectory: permission denied (Permission denied)
>
-- removeDirectory dir removes an existing directory dir.
> D.removeDirectory "/tmp/testdir"
> D.removeDirectory "/tmp/testdir"
*** Exception: /tmp/testdir: removeDirectory: does not exist (No such file or directory)
>
-- Similar to listDirectory, but always includes the special entries
-- (. and ..). (This applies to Windows as well.)
> :t D.getDirectoryContents "/boot"
D.getDirectoryContents "/boot" :: IO [FilePath]
>
> fmap (take 2) (D.getDirectoryContents "/boot" )
["initrd.img-3.19.0-37-generic","config-3.19.0-21-generic"]
>
> take 2 <$> D.getDirectoryContents "/boot"
["initrd.img-3.19.0-37-generic","config-3.19.0-21-generic"]
>
> D.getDirectoryContents "/boot" >>= mapM_ putStrLn
initrd.img-3.19.0-37-generic
config-3.19.0-21-generic
System.map-3.19.0-39-generic
abi-3.19.0-18-generic
...
> D.getDirectoryContents "/boot" >>= \rows -> return (take 10 rows) >>= mapM_ putStrLn
initrd.img-3.19.0-37-generic
config-3.19.0-21-generic
System.map-3.19.0-39-generic
...
>
> let displayDir path = D.getDirectoryContents path >>= \rows -> return (take 10 rows) >>= mapM_ putStrLn
>
> displayDir "/boot"
initrd.img-3.19.0-37-generic
config-3.19.0-21-generic
System.map-3.19.0-39-generic
...
-- Obtain the current working directory as an absolute path.
--
> :t D.getCurrentDirectory
D.getCurrentDirectory :: IO FilePath
>
> D.getCurrentDirectory
"/home/tux"
>
-- Change the working directory to the given path.
--
> :t D.setCurrentDirectory
D.setCurrentDirectory :: FilePath -> IO ()
>
-- Returns the current user's home direct
--
> D.getHomeDirectory
"/home/tux"
>
> D.getUserDocumentsDirectory
"/home/tux"
>
> D.getTemporaryDirectory
"/tmp"
>
-- copyFile old new copies the existing file from old to new. If the
-- new file already exists, it is atomically replaced by the old
-- file. Neither path may refer to an existing directory. The
-- permissions of old are copied to new, if possible.
> :t D.copyFile
D.copyFile :: FilePath -> FilePath -> IO ()
>
>
> D.copyFile "/etc/lsb-release" "/tmp/test.txt"
>
> readFile "/tmp/test.txt" >>= putStrLn
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=15.04
DISTRIB_CODENAME=vivid
DISTRIB_DESCRIPTION="Ubuntu 15.04"
{-
removeFile file removes the directory entry for an existing file file,
where file is not itself a directory. The implementation may specify
additional constraints which must be satisfied before a file can be
removed (e.g. the file may not be in use by other processes).
-}
> :t D.removeFile
D.removeFile :: FilePath -> IO ()
>
> D.removeFile "/tmp/test.txt"
> D.removeFile "/tmp/test.txt"
*** Exception: /tmp/test.txt: removeLink: does not exist (No such file or directory)
>
{-
Given an executable file name, searches for such file in the
directories listed in system PATH. The returned value is the path to
the found executable or Nothing if an executable with the given name
was not found. For example (findExecutable "ghc") gives you the path
to GHC.
-}
> D.findExecutable "java"
Just "/opt/bin/java"
>
> D.findExecutable "javac"
Just "/opt/java/bin/javac"
> D.findExecutable "javaasdas"
Nothing
>
{-
Given a file name, searches for the file and returns a list of all
occurences that are executable.
-}
> D.findExecutables "java"
["/opt/bin/java","/opt/bin/java","/usr/bin/java","/opt/java/bin/java"]
>
> D.findExecutables "ghci"
["/usr/bin/ghci"]
>
{-
Given a file name, searches for the file on the given paths and
returns a list of all occurences that are executable.
-}
> :t D.findFile
D.findFile :: [FilePath] -> String -> IO (Maybe FilePath)
>
> D.findFiles ["/opt/bin", "/usr/bin"] "java"
["/opt/bin/java","/usr/bin/java"]
>
> D.findFiles ["/opt/bin", "/usr/bin"] "jasadva"
[]
-- The operation doesFileExist returns True if the argument file
-- exists and is not a directory, and False otherwise.
> D.doesFileExist "/etc/fstab"
True
>
> D.doesFileExist "/etc/fstaASDb"
False
>
{-
The operation doesDirectoryExist returns True if the argument file
exists and is either a directory or a symbolic link to a directory,
and False otherwise.
-}
>
> D.doesDirectoryExist "/etc"
True
> D.doesDirectoryExist "/etc/Dummy"
False
>
-- The getPermissions operation returns the permissions for the file or directory.
--
> D.getPermissions "/etc/fstab"
Permissions {readable = True, writable = False, executable = False, searchable = False}
>
Information about the characteristics of the host system lucky enough to run your program.
> import qualified System.Info as I
>
> I.os
"linux"
>
> I.arch
"i386"
>
> I.compilerName
"ghc"
>
> I.compilerVersion
Version {versionBranch = [7,6], versionTags = []}
>
> :t I.compilerVersion
I.compilerVersion :: Data.Version.Version
>
> import qualified System.Process as P
>
{-
Creates a new process to run the specified command with the given
arguments, and wait for it to finish. If the command returns a
non-zero exit code, an exception is raised.
-}
> P.callProcess "date" []
Ter Fev 23 12:29:42 BRT 2016
> :t P.callProcess "date" []
P.callProcess "date" [] :: IO ()
>
> P.callProcess "dadsfte" []
*** Exception: dadsfte: callProcess: runInteractiveProcess: exec: does not exist (No such file or directory)
>
> P.callProcess "uname" ["-a"]
Linux tuxhorse 3.19.0-39-generic #44-Ubuntu SMP Tue Dec 1 14:38:23 UTC 2015 i686 i686 i686 GNU/Linux
>
{-
Creates a new process to run the specified shell command. If the
command returns a non-zero exit code, an exception is raised.
-}
> P.callCommand "uname -a"
Linux tuxhorse 3.19.0-39-generic #44-Ubuntu SMP Tue Dec 1 14:38:23 UTC 2015 i686 i686 i686 GNU/Linux
>
> :t P.callCommand
P.callCommand :: String -> IO ()
>
{-
readProcess forks an external process, reads its standard output
strictly, blocking until the process terminates, and returns the
output string. The external process inherits the standard error.
readProcess Source
:: FilePath Filename of the executable (see RawCommand for details)
-> [String] any arguments
-> String standard input
-> IO String stdout
-}
> :t P.readProcess
P.readProcess :: FilePath -> [String] -> String -> IO String
>
> P.readProcess "uname" ["-r"] ""
"3.19.0-39-generic\n"
>
> kernelVersion <- P.readProcess "uname" ["-r"] ""
> kernelVersion
"3.19.0-39-generic\n"
> :t kernelVersion
kernelVersion :: String
>
{-
readProcessWithExitCode Source
:: FilePath Filename of the executable (see RawCommand for details)
-> [String] any arguments
-> String standard input
-> IO (ExitCode, String, String) exitcode, stdout, stderr
-}
>
> P.readProcessWithExitCode "uname" ["-a"] ""
(ExitSuccess,"Linux tuxhorse 3.19.0-39-generic #44-Ubuntu SMP Tue Dec 1 14:38:23 UTC 2015 i686 i686 i686 GNU/Linux\n","")
>
> P.readProcessWithExitCode "uname" ["-x"] ""
(ExitFailure 1,"","uname: invalid option -- 'x'\nTry 'uname --help' for more information.\n")
>
> P.readProcessWithExitCode "unasdame" ["-x"] ""
*** Exception: unasdame: readCreateProcessWithExitCode: runInteractiveProcess: exec: does not exist (No such file or directory)
>