{- Beispielprogramm Haskell File-I/O, "FileIO.hs" Das Programm liest und vergleicht zwei Dateien und schreibt die unterschiedlichen Zeilen in eine dritte oder auf die Konsole. Autor: Jost Berthold -} module Main where import System(getArgs, getProgName) import Monad(when) import IO -- alle Operationen mit Handles --------------------------------------------------------------------------- -- Gebrauchsanweisung usage :: String -> String usage name = "Beispielprogramm zur Datei- Ein- und Ausgabe\n" ++ " Benutzung: " ++ name ++ " [Ausgabedatei]" -- main Funktion main :: IO() main = do args <- getArgs if length args < 2 then do -- Gebrauchsanweisung ausgeben name <- getProgName putStrLn (usage name) else -- Dateien öffnen (Handles), Abbruch falls Fehler: do maybef1 <- openCatchNonExist (args!!0) if maybef1 == Nothing then putStrLn "Programm abgebrochen" else do let (Just f1) = maybef1 maybef2 <- openCatchNonExist (args!!1) if maybef2 == Nothing then do hClose f1 putStrLn "Programm abgebrochen" else do let (Just f2) = maybef2 outHdl <- if length args == 2 then return stdout -- vordefiniert, bereits offen else -- Datei zum Schreiben öffnen openFile (args!!2) WriteMode -- Header schreiben: hPutStrLn outHdl ("\t\tUnterschiedliche Zeilen\n" ++ "\t<: in "++ (args!!0) ++ "\n\t>: in " ++ (args!!1)) -- ganze Datei 1 lesen, hGetContents :: Handle -> IO String str1 <- hGetContents f1 cmpFiles (lines str1) f2 outHdl -- rekursiv: vergleiche Zeile aus Argument 1 mit Zeile, die aus handle gelesen wird. cmpFiles :: [String] -> Handle -> Handle -> IO () -- Datei 1 komplett gelesen: cmpFiles [] f2 out = do ende <- hIsEOF f2 if ende -- Datei 2 auch am Ende then return () -- fertig else do -- sonst: schreibe eine Zeile in l <- hGetLine f2 hPutStrLn out (">: " ++ l) cmpFiles [] f2 out -- noch Zeilen aus Datei 1 übrig: cmpFiles (l:ls) f2 out = do ende <- hIsEOF f2 if ende -- Datei 2 am Ende? then -- Rest von Datei 1 in schreiben -- do -- hPutStrLn out l -- cmpFiles ls f2 out -- oder schneller: kein weiterer Test mehr mapM_ (hPutStrLn out) (map ("<: " ++ ) (l:ls)) else -- Datei 2 noch nicht am Ende: do -- Zeile aus Datei 2 lesen und mit 1 vergleichen l2 <- hGetLine f2 when (l /= l2) -- nur ausführen, falls Test True ergibt ( do hPutStrLn out ("<: " ++ l) hPutStrLn out (">: " ++ l2) ) cmpFiles ls f2 out openCatchNonExist :: FilePath -> IO (Maybe Handle) openCatchNonExist file = catch (openFile file ReadMode >>= \h -> return (Just h)) (\e -> if isDoesNotExistError e then putStrLn (file ++ ": File does not exist.") >> return Nothing else ioError e)