Skip to content

Instantly share code, notes, and snippets.

@ijt
Created June 30, 2011 06:26
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save ijt/1055731 to your computer and use it in GitHub Desktop.
Haskell example of tailing a file
#!/usr/bin/env runhaskell
-- Example of tailing a file, using two communicating Haskell threads. It's not
-- really necessary to do this concurrently, but the approach here generalizes
-- nicely if we want to filter or transform the output.
import Control.Concurrent
import Control.Monad
import System.Environment
import System.Exit
import System.IO
import System.Posix.Files
type Line = String
usage = "usage: tailf file"
main = do
args <- getArgs
case args of
[] -> do
putStrLn usage
exitFailure
["-h"] -> do
putStrLn usage
exitSuccess
["--help"] -> do
putStrLn usage
exitSuccess
[path] -> do
c <- newEmptyMVar
forkIO (getLines path 0 c)
forever $ do
msg <- takeMVar c
putStr msg
-- |getLines tails the file, sending the lines back to the caller through the
-- passed-in MVar.
getLines :: FilePath -> Integer -> MVar Line -> IO ()
getLines path sizeSoFar mvar = do
stat <- getFileStatus path
let newSize = fromIntegral $ fileSize stat :: Integer
if newSize > sizeSoFar
then do
handle <- openFile path ReadMode
hSeek handle AbsoluteSeek sizeSoFar
newContents <- hGetContents handle
putMVar mvar newContents
getLines path newSize mvar
else do
getLines path sizeSoFar mvar
@radix
Copy link

radix commented Apr 14, 2015

A few comments. Apologies for doing so without solicitation, but I figure this could help others like me who are looking for a way to stream files in Haskell.

  • in the else condition of getLines, it will busyloop, using 100% CPU while it continuously checks if the file has changed, until some new data has been written to the file.
  • "lines" here is a misnomer, since this code isn't doing anything to split the input by lines. It'll just fetch arbitrary-sized chunks of data from the file. Accidents of buffering may make it look like you receive one or more complete lines at a time, but it's not guaranteed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment