– действие ввода-вывода, которое вернёт содержимое файла в результате. Функция похожа на функцию
>getContents
. Единственное отличие – функция
>getContents
читает со стандартного входа (то есть с терминала), в то время как функция
>hGetContents
принимает дескриптор файла, из которого будет происходить чтение. Во всех остальных смыслах они работают одинаково. Так же как и
>getContents
, наша функция
>hGetContents
не пытается прочитать весь файл целиком и сохранить его в памяти, но читает его по мере необходимости. Это очень удобно, поскольку мы можем считать, что идентификатор
>contents
хранит всё содержимое файла, но на самом деле содержимого файла в памяти нет. Так что даже чтение из очень больших файлов не отожрёт всю память, но будет считывать только то, что нужно, и тогда, когда нужно.
Обратите внимание на разницу между дескриптором, который используется для идентификации файла, и его содержимым. В нашей программе они привязываются к именам >handle
и >contents
. Дескриптор – это нечто, с помощью чего мы знаем, что есть наш файл. Если представить всю файловую систему в виде очень большой книги, а каждый файл в виде главы, то дескриптор будет чем-то вроде закладки, которая показывает нам, где мы в данный момент читаем (или пишем), в то время как идентификатор >contents
будет содержать саму главу.
С помощью вызова >putStr contents
мы распечатываем содержимое на стандартном выводе, а затем выполняем функцию >hClose
, которая принимает дескриптор и возвращает действие ввода-вывода, закрывающее файл. После открытия файла с помощью функции >openFile
вы должны закрывать файлы самостоятельно!
Использование функции withFile
То, что мы только что сделали, можно сделать и по-другому – с использованием функции >withFile
. Сигнатура этой функции:
>withFile :: FilePath –> IOMode –> (Handle –> IO a) –> IO a
Она принимает путь к файлу, режим открытия файла и некоторую функцию, принимающую дескриптор и возвращающую некое действие ввода-вывода. Функция >withFile
вернёт действие ввода-вывода, которое откроет файл, сделает с ним то, что нам нужно, и закроет его. Результат, помещённый в заключительном действии ввода-вывода, будет взят из результата переданной нами функции. С виду это может показаться сложным, но на самом деле всё просто, особенно если использовать анонимные функции. Вот как можно переписать предыдущий пример с использованием функции >withFile
:
>import System.IO
>main = do
> withFile "girlfriend.txt" ReadMode (\handle –> do
> contents <– hGetContents handle
> putStr contents)
Функция