[More on files John Goerzen **20070707172614] { addfile ./examples/ch06/fileimp.hs move ./examples/ch06/fileimp.hs ./examples/ch06/toupper-imp.hs addfile ./examples/ch06/hOpen.ghci move ./examples/ch06/hOpen.ghci ./examples/ch06/openFile.ghci hunk ./en/book-shortcuts.xml 45 +return"> +FilePath"> +IOMode"> +ReadMode"> +WriteMode"> +ReadWriteMode"> +AppendMode"> hunk ./en/ch06-io.xml 192 - FIXME: stdin / stdout - FIXME: deleting files, renaming them, directory contents + + Let's start with an imperative way to read and write files. This will + probably seem familiar to a while loop that you may + find in other languages. This isn't the best way to write it in + Haskell; later, you'll see examples of more Haskellish approaches. + + + &toupper-imp.hs:all; + + + Like every Haskell program, execution of this program begins as + main. Two files are opened: + input.txt is opened for reading, and + output.txt is opened for writing. Then we call + mainloop. + + + mainloop begins by checking to see if we're at the + end of file (EOF) for the input. If we are, then we return + () -- this function doesn't return any other specific + value. Otherwise, we read a line from the input. We write out the + same line to the output, after first converting it to uppercase. Then + we recursively call mainloop again to continue + processing the file. + + + Notice that &return; call. This is not really the same as &return; in + C or Python. In those languages, &return; is used to terminate + execution of the current function immediately, and to return a value to + the caller. In Haskell, &return; is the opposite of &larrow;. That + is, &return; takes a pure value and wraps it inside &IO;. Since every + I/O action must return some &IO; type, if your result came from pure + computation, you must use &return; to wrap it in &IO;. + + + Let's try running the program. We've got a file named + input.txt that looks like this: + + +This is ch06/input.txt + +Test Input +I like Haskell +Haskell is great +I/O is fun + +123456789 + + + Now, you can use runghc toupper-imp.hs and you'll + find output.txt in your directory. It should look + like this: + + +THIS IS CH06/INPUT.TXT + +TEST INPUT +I LIKE HASKELL +HASKELL IS GREAT +I/O IS FUN + +123456789 + + + More on openFile + + Let's use &ghci; to check on the type of &openFile;: + + &openFile.ghci:all; + + &FilePath; is simply another name for &String;. It is used in the + types of I/O functions to help clarify that the parameter is being + used as a filename, and not as regular data. + + + &IOMode; specifies how the file is to be managed. The possible + values for &IOMode; are listed in . + + FIXME: check formatting on this table for final book; openjade + doesn't render it well + + Possible IOMode Values + + + + + + + + + &IOMode; + Can read? + Can write? + Starting position + Notes + + + + + &ReadMode; + Yes + No + Beginning of file + File must exist already + + + &WriteMode; + No + Yes + Beginning of file + File is truncated if it already existed + + + &ReadWriteMode; + Yes + Yes + Beginning of file + File is created if it didn't exist; otherwise, existing + data is left intact + + + &AppendMode; + No + Yes + End of file + File is created if it didn't exist; otherwise, existing + data is left intact. + + + +
+ +
hunk ./en/ch06-io.xml 330 + FIXME: stdin / stdout + FIXME: deleting files, renaming them, directory contents hunk ./en/ch06-io.xml 396 + FIXME: return addfile ./examples/ch06/input.txt hunk ./examples/ch06/input.txt 1 +This is ch06/input.txt + +Test Input +I like Haskell +Haskell is great +I/O is fun + +123456789 hunk ./examples/ch06/openFile.ghci 1 +--# all +:m System.IO +:t openFile hunk ./examples/ch06/toupper-imp.hs 1 +{-- snippet all --} +-- ch06/toupper-imp.hs + +import System.IO +import Data.Char(toUpper) + +main = do + inh <- openFile "input.txt" ReadMode + outh <- openFile "output.txt" WriteMode + mainloop inh outh + hClose inh + hClose outh + +mainloop inh outh = + do ineof <- hIsEOF inh + if ineof + then return () + else do inpStr <- hGetLine inh + hPutStrLn outh (map toUpper inpStr) + mainloop inh outh +{-- /snippet all --} + }