Writing Files in Haskell

Here’s the translation of the Go code to Haskell, formatted in Markdown suitable for Hugo:

Writing files in Haskell follows similar patterns to the ones we saw earlier for reading.

import System.IO
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as C8

main :: IO ()
main = do
    -- To start, here's how to dump a string (or just bytes) into a file.
    let d1 = C8.pack "hello\nhaskell\n"
    BS.writeFile "/tmp/dat1" d1

    -- For more granular writes, open a file for writing.
    withFile "/tmp/dat2" WriteMode $ \handle -> do
        -- You can write ByteStrings as you'd expect.
        let d2 = C8.pack "some\n"
        BS.hPut handle d2
        putStrLn $ "wrote " ++ show (BS.length d2) ++ " bytes"

        -- A writeString function is also available.
        hPutStrLn handle "writes"
        putStrLn "wrote 7 bytes"

        -- hFlush to ensure all buffered operations have been applied to the underlying handle.
        hFlush handle

        -- Use BufferedIO for buffered writers.
        hSetBuffering handle (BlockBuffering Nothing)
        BS.hPut handle $ C8.pack "buffered\n"
        putStrLn "wrote 9 bytes"

        -- Use hFlush to ensure all buffered operations have been applied to the underlying handle.
        hFlush handle

Try running the file-writing code:

$ runhaskell writing-files.hs
wrote 5 bytes
wrote 7 bytes
wrote 9 bytes

Then check the contents of the written files:

$ cat /tmp/dat1
hello
haskell
$ cat /tmp/dat2
some
writes
buffered

In this Haskell version:

  1. We use Data.ByteString for efficient byte operations.
  2. The withFile function is used to safely open and close files.
  3. hPutStrLn is used instead of WriteString.
  4. hFlush is used to flush the buffer, similar to Sync in the original example.
  5. hSetBuffering is used to set up buffered I/O.

Note that Haskell’s strong type system and functional nature lead to some differences in how file I/O is handled compared to more imperative languages.

Next, we’ll look at applying some of the file I/O ideas we’ve just seen to the stdin and stdout streams.