haskell - Input and Output - Files and Streams

so far what we have dealt with are all functions and streams. now we might get our hand wet dealing with Files and Streams. 

 

what we will discusses in this post includes:  

 

getContent and getChar .... 

getContents  is lazy which means it won't read content until we actually use the content read from the call. (how is the laziness implemented)

let's see first one example. 

import Data.Char  
  
main = do 
    main2
--    contents <-  getContents
--    putStr (map toUpper contents)


main2 = do 
    contents <- getContents  
    putStr (shortLinesOnly contents)  
  
shortLinesOnly :: String -> String  
shortLinesOnly input =   
    let allLines = lines input  
        shortLines = filter (\line -> length line < 10) allLines  
        result = unlines shortLines  
    in  result  

 

and again yet another example on how to use getContent to transform lines to upper case. 

-- file 
--  files_streams.hs
-- descrpition: 
--  Files and Streams
import Control.Monad  
import Data.Char  
  
main = forever $ do  
    putStr "Give me some input: "  
    l <- getLine  
    putStrLn $ map toUpper l  

-- with getContents

main2 = do 
   contents <- getContents
   putStr (map toUpper contents)

 

interact

This pattern of getting some string from the input, transforming it with a function and then outputting that is so common that there exists a function which makes that even easier, called interact

 

below are some example with interact. 

case 1)

 

main = interact shortLinesOnly  
  
shortLinesOnly :: String -> String  
shortLinesOnly input =   
    let allLines = lines input  
        shortLines = filter (\line -> length line < 10) allLines  
        result = unlines shortLines  
    in  result

 and 

case 2)

 

main2 = interact $ unlines . filter ((<10) . length) . lines

 and case 3)

 

respondPalindromes = unlines . map (\xs -> if isPalindrome xs then "palindrome" else "not a palindrome") . lines  
    where   isPalindrome xs = xs == reverse xs  
main = interact respondPalindromes

 

Now, let's deal with files. 

 

so before start, suppose the runtime has define the following types and type synonyms. 

type FilePath = String  

data IOMode = ReadMode | WriteMode | AppendMode | ReadWriteMode  

 

hGetContents, hClose

we get contents from files handles with hGetContents call. hClose close a file handle. 

 

 

withFile 

it is so common that you will first open a file, get the contents (read) or write the contents, and close the file , so there is a withFile call. 

-- file 
--  hGetContents_io.hs
-- descrpition: 
--  unlike the getContents_io.hs , which automatically read from the stdin, gGetContents will read from aHandle
import Data.Char  

import System.IO

main = do 
    withFile "girlfriend.txt" ReadMode (\handle -> do 
       contents <- hGetContents handle
       putStr contents) 

-- haskell's way of withFile pattern, which is more like the Dispose pattern used quit common in C# language


-- and if you will implements the code of hGetHandle it is like this: 


withFile' :: FilePath -> IOMode -> (Handle -> IO a) -> IO a  
withFile' path mode f = do  
    handle <- openFile path mode   
    result <- f handle  
    hClose handle  
    return result  

 

 

hGetLine, hPutStr, hPutStrLn, hGetChar

they are like the counterPart without the h... we will ignore this part. 

 

 

readFile and writeFile, appendFile 

readFile, writeFile and appendFile which takes a string to write to that file and returns an I/O action that will do the writing. 

readFile 

main = do 
   contents <- readFile "girlfriend.txt"
   putStr contents

 writeFile 

import System.IO
import Data.Char

main = do 
   contents <- readFile "girlfriend.txt"
   writeFile "girlfriendcaps.txt" (map toUpper contents)

 appendFile 

import System.IO     
    
main = do     
    todoItem <- getLine  
    appendFile "todo.txt" (todoItem ++ "\n")  

 

hSetBuffering 

you can control the lower-level behavior. here is the code shows that you can control the behavior with the hSetBuffering 

-- file 
--   hSetBuffering_io.hs
-- descrpition: 
--    It takes a handle and a BufferMode and returns an I/O action that sets the buffering.  It takes a handle and a BufferMode and returns an I/O action that sets the buffering. 
--   an example of the value to the hSetBuffering is like this:
--     NoBuffering, LineBuffering or BlockBuffering (Maybe Int). 
-- 

import System.IO

main = do 
  withFile "something.txt" ReadMode (\handle -> do 
    hSetBuffering handle $ BlockBuffering (Just 2048)
    contents <- hGetContents handle
    putStr contents)

-- you may as well try the hFush function which will flush the buffers that is in the end writeBuffer

 

openTempFile, hFlush 

an example use the following...

 

-- file
--   remove_todo.hs
-- description:
--   remove some items from the todo List 
import System.IO  
import System.Directory  
import Data.List  
  
main = do        
    handle <- openFile "todo.txt" ReadMode  
    (tempName, tempHandle) <- openTempFile "." "temp"  
    contents <- hGetContents handle  
    let todoTasks = lines contents     
        numberedTasks = zipWith (\n line -> show n ++ " - " ++ line) [0..] todoTasks     
    putStrLn "These are your TO-DO items:"  
    putStr $ unlines numberedTasks  
    putStrLn "Which one do you want to delete?"     
    numberString <- getLine     
    let number = read numberString     
        newTodoItems = delete (todoTasks !! number) todoTasks     
    hPutStr tempHandle $ unlines newTodoItems  
    hClose handle  
    hClose tempHandle  
    removeFile "todo.txt"   -- remove a file from the FS
    renameFile tempName "todo.txt"  -- rename A file to B file

 

 

你可能感兴趣的:(haskell)