Мы помним, что тип FilePath – это просто удобное обозначение для String. Функция readFile принимает путь к файлу и возвращает действие ввода-вывода, которое прочитает файл (лениво, конечно же) и свяжет содержимое файла в виде строки с некоторым именем. Обычно это более удобно, чем вызывать функцию openFile и связывать дескриптор с именем, а затем вызывать функцию hGetContents. Вот как мы могли бы переписать предыдущий пример с использованием readFile:

import System.IO

main = do

   contents <– readFile "girlfriend.txt"

   putStr contents

Так как мы не получаем дескриптор файла в качестве результата, то не можем закрыть его сами. Если мы используем функцию readFile, за нас это сделает язык Haskell.

Функция writeFile имеет тип

writeFile :: FilePath –> String –> IO ()

Она принимает путь к файлу и строку для записи в файл и возвращает действие ввода-вывода, которое выполнит запись. Если такой файл уже существует, перед записью он будет обрезан до нулевой длины. Вот как получить версию файла girlfriend.txt в верхнем регистре и записать её в файл girlfriendcaps.txt:

import System.IO

import Data.Char

main = do

   contents <– readFile "girlfriend.txt"

   writeFile "girlfriendcaps.txt" (map toUpper contents)

Функция appendFile имеет ту же сигнатуру, что и writeFile, и действует почти так же. Она только не обрезает уже существующий файл до нулевой длины перед записью, а добавляет новое содержимое в конец файла.

<p>Список дел</p>

Воспользуемся функцией appendFile на примере написания программы, которая добавляет в текстовый файл, содержащий список наших дел, новое задание. Допустим, у нас уже есть такой файл с названием todo.txt, и каждая его строка соответствует одному заданию.

Наша программа будет читать из стандартного потока ввода одну строку и добавлять её в конец файла todo.txt:

import System.IO

main = do

   todoItem <– getLine

   appendFile "todo.txt" (todoItem ++ "\n")

Обратите внимание на добавление символа конца строки вручную, функция getLine возвращает строку без него.

Сохраните этот файл с именем appendtodo.hs, скомпилируйте его и несколько раз запустите.

$ ./appendtodo

Погладить посуду

$ ./appendtodo

Помыть собаку

$ ./appendtodo

Вынуть салат из печи

$ cat todo.txt

Погладить посуду

Помыть собаку

Вынуть салат из печи

ПРИМЕЧАНИЕ. Программа cat в Unix-подобных системах используется для вывода содержимого текстового файла на терминал. В Windows можно воспользоваться командой type или посмотреть содержимое файла в любом текстовом редакторе.

<p>Удаление заданий</p>

Мы уже написали программу, которая добавляет новый элемент к списку заданий в файл todo.txt; теперь напишем программу для удаления элемента. Мы применим несколько новых функций из модуля 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"

Сначала мы читаем содержимое файла todo.txt и связываем его с именем contents. Затем разбиваем всё содержимое на список строк. Список todoTasks выглядит примерно так:

Перейти на страницу:

Похожие книги