~~DISCUSSION ~~
====== Filesystem IO and streams ======
*example:
* code, module FileSystem
{-|
Description : is to provides a generalised, abstract, and save interface to the files system.
Copyright : (c) Jörg K.-H. W. Brüggmann, 2021
License : CC0 1.0 Universal
Maintainer : ...@...
Stability : experimental
Portability : POSIX
* traits:
* abstractions:
* uniform types for identification of input and output streams ('Inp', 'Out')
* higher order functions encapsulated in data types ('DataReader', 'DataWriter') are applied on streams
* can not cause error by "invalid characters", as long as the stream handler functions do not cause them
* supports the following file system features:
* deletion of files
* processing (read and write at once) and writing streams
* supports the following data types:
* Octets
NOTE: There is no isolated read function like the write function, because this would lead to errors like "illegal operation (delayed read on closed handle)".
Background: The function hGetContents needs an open file handle, that may be closed before the lazy String has been evaluated.
* example
@
import qualified FileSystem as FS
import qualified System.IO as SysIo
main :: IO ()
main =
FS.processData
(FS.DataReader (FS.FileInp ".\\test\\a.txt") SysIo.hGetContents)
[
FS.DataWriter (FS.FileOut ".\\test\\b.txt") SysIo.hPutStr,
FS.DataWriter FS.StdOut SysIo.hPutStr,
FS.DataWriter FS.StdErr SysIo.hPutStr
]
@
* copies the file "a.txt" in ".\test" to "b.txt"
* sends the file content of "a.txt" also to 'stdout', and 'stderr'
* will not cause uncaught exception caused by "invalid characters"
-}
module FileSystem (
Inp(..),
Out(..),
DataReader(..),
DataWriter(..),
removeFileIfExists,
processData,
writeToData
) where
import qualified System.IO as SysIo
import qualified System.IO.Error as Err
import qualified Control.Exception as Excp
import qualified System.Directory as Dir
-- input streams
data Inp =
StdInp
| FileInp String
deriving (Eq, Show)
-- output streams
data Out =
NullOut
| StdOut
| StdErr
| FileOut String
deriving (Eq, Show)
removeFileIfExists :: FilePath -> IO ()
removeFileIfExists fileName = Dir.removeFile fileName `Excp.catch` handleExists
where
handleExists :: Err.IOError -> IO ()
handleExists e | Err.isDoesNotExistError e = return ()
| otherwise = Excp.throwIO e
data DataReader s =
DataReader {
rinp :: Inp,
rfRead :: (SysIo.Handle -> IO s) }
data DataWriter s =
DataWriter {
rout :: Out,
rfWrite :: (SysIo.Handle -> s -> IO ()) }
processData :: (DataReader a) -> [DataWriter a] -> IO ()
processData (DataReader StdInp f) lwrt =
do
dt <- f SysIo.stdin
processData' dt lwrt
processData (DataReader (FileInp sFileName) f) lwrt =
do
hFile <- SysIo.openFile sFileName SysIo.ReadMode
dt <- f hFile
processData' dt lwrt
SysIo.hClose hFile
processData' :: a -> [DataWriter a] -> IO ()
processData' x [] = return ()
processData' x (wrt:lrwrt) =
do
writeToData wrt x
processData' x lrwrt
writeToData :: (DataWriter a) -> a -> IO ()
writeToData (DataWriter NullOut _) _ = return ()
writeToData (DataWriter StdOut f) x = f SysIo.stdout x
writeToData (DataWriter StdErr f) x = f SysIo.stderr x
writeToData (DataWriter (FileOut sFileName) f) x =
do
hFile <- SysIo.openFile sFileName SysIo.WriteMode
f hFile x
SysIo.hClose hFile
* code, use case of files system
import qualified FileSystem as FS
import qualified System.IO as SysIo
main :: IO ()
main =
FS.processData
(FS.DataReader (FS.FileInp ".\\test\\a.txt") SysIo.hGetContents)
[
FS.DataWriter (FS.FileOut ".\\test\\b.txt") SysIo.hPutStr,
FS.DataWriter FS.StdOut SysIo.hPutStr,
FS.DataWriter FS.StdErr SysIo.hPutStr
]
* compiles, error and warning free, with compiler: GHC 8.10.4, using compiler option -Wall
* executes with output as file copy of "a.txt" to "b.txt", ''stdout'', and ''stderr''
* example, with conversions
* code:
import qualified FileSystem as FS
import qualified System.IO as SysIo
import qualified Data.Char as Ch
main :: IO ()
main =
FS.processData
(FS.DataReader (FS.FileInp ".\\test\\a.txt") hGetToUpper)
[
FS.DataWriter (FS.FileOut ".\\test\\b.txt") SysIo.hPutStr,
FS.DataWriter FS.StdOut hPutToLower,
FS.DataWriter FS.StdErr SysIo.hPutStr
]
hGetToUpper :: SysIo.Handle -> IO String
hGetToUpper h =
do
s <- SysIo.hGetContents h
return (fmap Ch.toUpper s)
hPutToLower :: SysIo.Handle -> String -> IO ()
hPutToLower h s = SysIo.hPutStr h (fmap Ch.toLower s)
* input, file "a.txt"
The quick brown fox jumps over the lazy dog.
* output, in terminal:
the quick brown fox jumps over the lazy dog.
THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.
* output, file "b.txt":
THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.
===== ✎ =====
~~DISCUSSION~~