Files and IO

Contents
Read a file
Write a file
lines and unlines
Handles and withFile

Read a file

readFile returns the whole file as one string inside IO. It is lazy: the file is opened and read as the string is consumed, which is convenient and occasionally surprising when the file changes underneath:

main :: IO () main = do text <- readFile "input.txt" putStrLn ("bytes: " ++ show (length text))

A missing file raises an IOException at runtime. Lesson 46 shows how to catch it; for now, keep the filename in a variable so the error message is easy to reproduce.

Write a file

writeFile replaces the file and appendFile adds to the end. Both take the content as a plain string, so the pure part of the program builds it first:

main = do writeFile "out.txt" "first line\n" appendFile "out.txt" "second line\n"

The newline is explicit. Nothing appends it for you, which is why the helper functions in the next section exist.

lines and unlines

Two functions convert between a string and a list of lines. lines splits on newlines and drops the terminators, and unlines puts them back:

lines "a\nb\n" -- ["a","b"] unlines ["a","b"] -- "a\nb\n" -- number every line of a file numbered text = unlines [ show n ++ ": " ++ line | (n, line) <- zip [1..] (lines text) ]

numbered is pure, so it can be tested with a string literal and no file at all. That is the shell pattern from lesson 33 applied to text processing.

Handles and withFile

For a file read in several passes, open a handle and close it with a bracketed helper. withFile closes the handle even if the body throws:

import System.IO main = withFile "out.txt" WriteMode \h -> do hPutStrLn h "written through a handle"

The manual version calls openFile and hClose with no guarantee about the second one. Prefer the bracketed form, and use Data.Text.IO instead of String once files grow past a few megabytes.

Next: Modules and imports

Article author: Arthur Isaev

Related articles
Haskell
Haskell course: zero to hero in 50 lessons
What is Haskell and why it matters
Install the toolchain with GHCup
GHCi: the interactive shell
Your first program
Values with let and where
Types and type signatures
Functions and application
Currying and partial application
Operators, sections, and fixity
if, guards, and pattern guards
case expressions
Pattern matching
Tuples
Lists
Ranges and enumeration
List comprehensions
Recursion replaces loops
map, filter, and foldr
Lambdas and composition
Type classes
Parametric polymorphism
Maybe and null safety
Either and recoverable errors
data: product types
data: sum types
Records
newtype and type synonyms
Recursive data: binary trees
Functor
Applicative
Monad
do notation
IO and purity
Files and IO
Modules and imports
Cabal projects
Dependencies
Testing with HUnit
Property testing with QuickCheck
Laziness and infinite lists
Strictness and space leaks
Folds
Monoids
Traversable
Monad transformers
Errors and exceptions
Concurrency
Parsing with Megaparsec
Capstone: a todo CLI
Hero roadmap: the whole course on one page

Search this site

Channel @aofeed Chat @aofeedchat

Contacts and cooperation:
I recommend our hosting beget.com
Write to info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: