Мы помним, что тип FilePath
– это просто удобное обозначение для String
. Функция readFile
принимает путь к файлу и возвращает действие ввода-вывода, которое прочитает файл (лениво, конечно же) и свяжет содержимое файла в виде строки с некоторым именем. Обычно это более удобно, чем вызывать функцию openFile
и связывать дескриптор с именем, а затем вызывать функцию hGetContents
. Вот как мы могли бы переписать предыдущий пример с использованием readFile
:
import System.IO
main = do
contents <– readFile "girlfriend.txt"
putStr contents
Так как мы не получаем дескриптор файла в качестве результата, то не можем закрыть его сами. Если мы используем функцию readFile
, за нас это сделает язык Haskell.
Функция writeFile
имеет тип
writeFile :: FilePath –> String –> IO ()
Она принимает путь к файлу и строку для записи в файл и возвращает действие ввода-вывода, которое выполнит запись. Если такой файл уже существует, перед записью он будет обрезан до нулевой длины. Вот как получить версию файла
import System.IO
import Data.Char
main = do
contents <– readFile "girlfriend.txt"
writeFile "girlfriendcaps.txt" (map toUpper contents)
Функция appendFile
имеет ту же сигнатуру, что и writeFile
, и действует почти так же. Она только не обрезает уже существующий файл до нулевой длины перед записью, а добавляет новое содержимое в конец файла.
Список дел
Воспользуемся функцией appendFile
на примере написания программы, которая добавляет в текстовый файл, содержащий список наших дел, новое задание. Допустим, у нас уже есть такой файл с названием
Наша программа будет читать из стандартного потока ввода одну строку и добавлять её в конец файла
import System.IO
main = do
todoItem <– getLine
appendFile "todo.txt" (todoItem ++ "\n")
Обратите внимание на добавление символа конца строки вручную, функция getLine
возвращает строку без него.
Сохраните этот файл с именем
$ ./appendtodo
Погладить посуду
$ ./appendtodo
Помыть собаку
$ ./appendtodo
Вынуть салат из печи
$ cat todo.txt
Погладить посуду
Помыть собаку
Вынуть салат из печи
ПРИМЕЧАНИЕ. Программа cat
в Unix-подобных системах используется для вывода содержимого текстового файла на терминал. В Windows можно воспользоваться командой type
или посмотреть содержимое файла в любом текстовом редакторе.
Удаление заданий
Мы уже написали программу, которая добавляет новый элемент к списку заданий в файл System.Directory
и одну новую функцию из модуля System.IO
; их работа будет объяснена позднее.
import System.IO
import System.Directory
import Data.List
main = do
contents <– readFile "todo.txt"
let todoTasks = lines contents
numberedTasks = zipWith (\n line –> show n ++ " – " ++ line)
[0..] todoTasks
putStrLn "Ваши задания:"
mapM_ putStrLn numberedTasks
putStrLn "Что вы хотите удалить?"
numberString <– getLine
let number = read numberString
newTodoItems = unlines $ delete (todoTasks !! number) todoTasks
(tempName, tempHandle) <– openTempFile "." "temp"
hPutStr tempHandle newTodoItems
hClose tempHandle
removeFile "todo.txt"
renameFile tempName "todo.txt"
Сначала мы читаем содержимое файла todoTasks
выглядит примерно так: