System.IO
| Авторские права | (c) The University of Glasgow 2001 |
|---|---|
| Лицензия | в стиле BSD (см. файл libraries/base/LICENSE) |
| Сопровождающий | libraries@haskell.org |
| Стабильность | стабильный |
| Переносимость | переносимый |
| Безопасный Haskell | Safe |
| Язык | Haskell2010 |
Описание
Стандартный API ввода-вывода.
Примеры
Примечание: некоторые примеры из этого модуля не работают в ghci «как есть». Это связано с тем, что использование stdin в сочетании с ленивым вводом-выводом некорректно работает в интерактивном режиме.
Строки, начинающиеся с >, обозначают stdin, а ^D сигнализирует о конце файла.
Пример
ghci> foo > input output > input^D output
Монада IO
Значение типа IO a — это вычисление, которое при выполнении выполняет некоторые операции ввода-вывода, прежде чем вернуть значение типа a.
На самом деле существует только один способ «выполнить» действие ввода-вывода: связать его с Main.main в вашей программе. Когда программа запускается, операции ввода-вывода будут выполнены. Выполнять ввод-вывод из произвольной функции нельзя, если только сама эта функция не принадлежит монаде IO и не вызывается в какой-либо точке, прямо или косвенно, из Main.main.
IO — это монада, поэтому действия IO можно объединять с помощью do-нотации или операций >> и >>= из класса Monad.
Экземпляры
| Alternative IO Исходный код |
Возвращает результат первого действия Начиная с: base-4.9.0.0 |
Определено в GHC.Internal.Base Методыempty :: IO a Исходный код (<|>) :: IO a -> IO a -> IO a Исходный код some :: IO a -> IO [a] Исходный код many :: IO a -> IO [a] Исходный код | |
| Applicative IO Исходный код | Начиная с: base-2.1 |
Определено в GHC.Internal.Base Методыpure :: a -> IO a Исходный код (<*>) :: IO (a -> b) -> IO a -> IO b Исходный код liftA2 :: (a -> b -> c) -> IO a -> IO b -> IO c Исходный код (*>) :: IO a -> IO b -> IO b Исходный код (<*) :: IO a -> IO b -> IO a Исходный код | |
| Functor IO Исходный код | Начиная с: base-2.1 |
Определено в GHC.Internal.Base | |
| Monad IO Исходный код | Начиная с: base-2.1 |
Определено в GHC.Internal.Base Методы(>>=) :: IO a -> (a -> IO b) -> IO b Исходный код (>>) :: IO a -> IO b -> IO b Исходный код return :: a -> IO a Исходный код | |
| MonadPlus IO Исходный код |
Возвращает результат первого действия Начиная с: base-4.9.0.0 |
Определено в GHC.Internal.Base | |
| MonadFail IO Исходный код | Начиная с: base-4.9.0.0 |
Определено в GHC.Internal.Control.Monad.Fail Методыfail :: HasCallStack => String -> IO a Исходный код | |
| MonadFix IO Исходный код | Начиная с: base-2.1 |
Определено в GHC.Internal.Control.Monad.Fix Методыmfix :: (a -> IO a) -> IO a Исходный код | |
| MonadIO IO Исходный код | Начиная с: base-4.9.0.0 |
Определено в GHC.Internal.Control.Monad.IO.Class МетодыliftIO :: IO a -> IO a Исходный код | |
| GHCiSandboxIO IO Исходный код | Начиная с: base-4.4.0.0 |
Определено в GHC.Internal.GHCi МетодыghciStepIO :: IO a -> IO a Исходный код | |
| Quasi IO Исходный код | |
Определено в Text.Printf | |
| a ~ () => PrintfType (IO a) Исходный код | С версии: base-4.7.0.0 |
Определено в Text.Printf | |
| Monoid a => Monoid (IO a) Исходный код | С версии: base-4.9.0.0 |
Определено в GHC.Internal.Base Методыmempty :: IO a Исходный код mappend :: IO a -> IO a -> IO a Исходный код mconcat :: [IO a] -> IO a Исходный код | |
| Semigroup a => Semigroup (IO a) Исходный код | С версии: base-4.10.0.0 |
Определено в GHC.Internal.Base Методы(<>) :: IO a -> IO a -> IO a Исходный код sconcat :: NonEmpty (IO a) -> IO a Исходный код stimes :: Integral b => b -> IO a -> IO a Исходный код | |
fixIO :: (a -> IO a) -> IO a Исходный код
Эта операция может завершиться ошибкой в следующем случае:
-
FixIOExceptionесли функция, переданная вfixIO, исследует свой аргумент.
Примеры
действие IO выполняется только один раз. Рекурсия применяется только к значениям.
>>> take 3 <$> fixIO (\x -> putStr ":D" >> (:x) <$> readLn @Int) :D 2 [2,2,2]
Если мы требуем строгого вычисления значения, как и в случае с fix, завершения не происходит:
>>> fixIO (\x -> putStr x >> pure ('x' : x))
* hangs forever *
Мы можем замкнуть рекурсивную структуру внутри IO с помощью fixIO:
data Node = MkNode Int (IORef Node) foo :: IO () foo = do p <- fixIO (p -> newIORef (MkNode 0 p)) q <- output p r <- output q _ <- output r pure () output :: IORef Node -> IO (IORef Node) output ref = do MkNode x p <- readIORef ref print x pure p
>>> foo 0 0 0
Файлы и дескрипторы
type FilePath = String Исходный код
Имена файлов и каталогов представлены значениями типа String, точное значение которого зависит от операционной системы. Файлы можно открыть, получив дескриптор, который затем можно использовать для работы с содержимым файла.
data Handle Исходный код
В Haskell определены операции чтения символов из файлов и записи символов в файлы, представленные значениями типа Handle. Каждое значение этого типа является дескриптором: записью, используемой средой выполнения Haskell для управления вводом-выводом объектов файловой системы. Дескриптор обладает как минимум следующими свойствами:
- управляет ли он вводом, выводом или и тем и другим;
- открыт ли он, закрыт или полузакрыт;
- поддерживает ли объект позиционирование;
- отключена ли буферизация или включена построчно либо блоками;
- наличие буфера (длина которого может быть равна нулю).
У большинства дескрипторов также есть текущая позиция ввода-вывода, указывающая, где будет выполнена следующая операция ввода или вывода. Дескриптор является доступным для чтения, если он управляет только вводом или вводом и выводом; аналогично, он является доступным для записи, если управляет только выводом или вводом и выводом. Дескриптор открыт сразу после создания. После закрытия его нельзя использовать ни для ввода, ни для вывода, хотя реализация не может повторно использовать выделенную для него память, пока на него остаются ссылки. Дескрипторы принадлежат к классам Show и Eq. Строка, полученная при отображении дескриптора, зависит от системы; она должна содержать достаточно информации, чтобы идентифицировать дескриптор при отладке. Согласно ==, дескриптор равен только самому себе; попытки сравнить внутреннее состояние разных дескрипторов на равенство не предпринимаются.
Экземпляры
| Eq Handle Исходный код | С версии: base-4.1.0.0 |
Определено в GHC.Internal.IO.Handle.Types | |
| Show Handle Исходный код | С версии: base-4.1.0.0 |
Определено в GHC.Internal.IO.Handle.Types МетодыshowsPrec :: Int -> Handle -> ShowS Исходный код show :: Handle -> String Исходный код showList :: [Handle] -> ShowS Исходный код | |
Примечание о GHC: Handle будет автоматически закрыт, когда сборщик мусора обнаружит, что программа больше на него не ссылается. Однако обычно не рекомендуется полагаться на такое поведение: работа сборщика мусора непредсказуема. По возможности используйте явный hClose, чтобы закрывать Handle после того, как они больше не нужны. В настоящее время GHC не пытается освобождать файловые дескрипторы при их исчерпании; вы сами должны следить за тем, чтобы этого не происходило.
Стандартные дескрипторы
Во время инициализации программы выделяются три дескриптора, изначально открытые.
stdin — дескриптор, управляющий стандартным вводом программы.
stdout — дескриптор, управляющий стандартным выводом программы.
stderr — дескриптор, управляющий стандартным потоком ошибок программы.
Открытие и закрытие файлов
Открытие файлов
Аргументы
| :: FilePath | Путь к файлу, который нужно открыть |
| -> IOMode | Режим, в котором нужно открыть файл |
| -> (Handle -> IO r) | Действие, выполняемое с полученным дескриптором |
| -> IO r |
Вычисление withFile path mode action открывает файл, выполняет action с полученным дескриптором, а затем закрывает файл.
Даже если внутри action возникает исключение, файл всё равно будет закрыт. Поэтому withFile path mode act предпочтительнее, чем
openFile path mode >>= (\hdl -> act hdl >>= hClose hdl)
См. также: bracket
Аргументы
| :: FilePath | Путь к файлу, который следует открыть |
| -> IOMode | Режим, в котором следует открыть файл |
| -> IO Handle |
Вычисление openFile path mode возвращает дескриптор файла, который можно использовать для взаимодействия с файлом.
Дескриптор открыт в текстовом режиме с localeEncoding. Кодировку можно изменить с помощью hSetEncoding.
См. openFile
Конструкторы
| ReadMode | |
| WriteMode | |
| AppendMode | |
| ReadWriteMode |
Экземпляры
Закрытие файлов
hClose :: Handle -> IO () Источник
Вычисление hClose hdl закрывает дескриптор hdl. Перед завершением вычисления, если hdl доступен для записи, его буфер сбрасывается, как и в случае с hFlush. Выполнение hClose для уже закрытого дескриптора не оказывает никакого эффекта; это не является ошибкой. Все остальные операции с закрытым дескриптором завершатся неудачей. Если hClose завершается неудачей по какой-либо причине, любые дальнейшие операции с дескриптором (кроме hClose) всё равно завершатся неудачей, как если бы hdl было успешно закрыто.
hClose — это прерываемая операция в смысле, описанном в Control.Exception. Если hClose прерывается асинхронным исключением во время сброса буферов, устройство ввода-вывода (например, файл) всё равно будет закрыто.
Особые случаи
Эти функции также экспортируются модулем Prelude.
readFile :: FilePath -> IO String Источник
Функция readFile читает файл и возвращает его содержимое в виде строки.
Файл читается лениво, по мере необходимости, как и в случае с getContents.
Эта операция может завершиться ошибкой по тем же причинам, что и hGetContents и openFile.
Примеры
>>> readFile "~/hello_world" "Greetings!"
>>> take 5 <$> readFile "/dev/zero" "\NUL\NUL\NUL\NUL\NUL"
readFile' :: FilePath -> IO String Источник
Функция readFile' читает файл и возвращает его содержимое в виде строки.
Она идентична readFile, но перед возвратом файл полностью считывается, как и в случае с getContents'.
Начиная с: base-4.15.0.0
writeFile :: FilePath -> String -> IO () Источник
Вычисление writeFile file str записывает строку str в файл file.
Эта операция может завершиться ошибкой по тем же причинам, что и hPutStr и withFile.
Примеры
>>> writeFile "hello" "world" >> readFile "hello" "world"
>>> writeFile "~/" "D:" *** Exception: ~/: withFile: inappropriate type (Is a directory)
appendFile :: FilePath -> String -> IO () Источник
Вычисление appendFile file str добавляет строку str в файл file.
Обратите внимание, что writeFile и appendFile записывают в файл строку в буквальном виде. Чтобы записать значение любого печатаемого типа, как в случае с print, сначала используйте функцию show для преобразования значения в строку.
Эта операция может завершиться ошибкой по тем же причинам, что и hPutStr и withFile.
Примеры
Следующий пример можно было бы написать эффективнее: вместо этого получить дескриптор с помощью openFile и использовать вычисления, позволяющие записывать данные в дескрипторы, например hPutStr.
>>> let fn = "hello_world" >>> in writeFile fn "hello" >> appendFile fn " world!" >> (readFile fn >>= putStrLn) "hello world!"
>>> let fn = "foo"; output = readFile' fn >>= putStrLn >>> in output >> appendFile fn (show [1,2,3]) >> output this is what's in the file this is what's in the file[1,2,3]
Блокировка файлов
Реализации должны, насколько это возможно, по крайней мере в пределах процесса Haskell, обеспечивать блокировку файлов по схеме «несколько читателей — один писатель». Иными словами, для одного файла может существовать либо множество дескрипторов, выполняющих чтение, либо только один дескриптор, выполняющий запись. Если какой-либо открытый или частично закрытый дескриптор использует файл для записи, для этого файла нельзя создать новый дескриптор. Если какой-либо открытый или частично закрытый дескриптор использует файл для чтения, новые дескрипторы можно создать только в том случае, если они не будут использовать файл для записи. Определение того, являются ли два файла одним и тем же файлом, зависит от реализации; обычно они должны считаться одним файлом, если у них одинаковый абсолютный путь и ни один из них не был переименован.
Предупреждение: операция readFile удерживает файл в частично закрытом состоянии до тех пор, пока не будет прочитано всё его содержимое. Поэтому попытка записать в файл (например, с помощью writeFile), ранее открытый функцией readFile, обычно завершится ошибкой isAlreadyInUseError.
hFileSize :: Handle -> IO Integer Источник
Для дескриптора hdl, связанного с физическим файлом, hFileSize hdl возвращает размер этого файла в 8-битных байтах.
hSetFileSize :: Handle -> Integer -> IO () Источник
hSetFileSize hdl size усекает физический файл, связанный с дескриптором hdl, до размера size байт.
Определение конца ввода
hIsEOF :: Handle -> IO Bool Источник
Для доступного для чтения дескриптора hdl функция hIsEOF hdl возвращает True, если из hdl больше нельзя получить данные или, в случае физического файла, если текущая позиция ввода-вывода совпадает с размером файла. В противном случае она возвращает False.
ПРИМЕЧАНИЕ: hIsEOF может блокироваться, поскольку ей необходимо попытаться прочитать данные из потока, чтобы определить, есть ли ещё данные для чтения.
Вычисление isEOF идентично hIsEOF, за исключением того, что оно работает только с stdin.
Операции с буферизацией
data BufferMode Источник
Поддерживаются три режима буферизации: построчная буферизация, блочная буферизация и отсутствие буферизации. Эти режимы работают следующим образом. При выводе элементы записываются из внутреннего буфера, то есть сбрасываются, в соответствии с режимом буферизации:
-
построчная буферизация: весь буфер вывода сбрасывается при выводе символа новой строки, переполнении буфера, вызове
hFlushили закрытии дескриптора. -
блочная буферизация: весь буфер записывается при его переполнении, вызове
hFlushили закрытии дескриптора. - без буферизации: данные вывода записываются немедленно и никогда не сохраняются в буфере.
Реализация может сбрасывать буфер чаще, но не реже, чем указано выше. После записи буфер вывода очищается.
Аналогично, ввод выполняется в соответствии с режимом буферизации дескриптора:
- построчная буферизация: если буфер дескриптора не пуст, следующий элемент извлекается из буфера; если буфер пуст, в него считываются символы до ближайшего символа новой строки включительно. Символы недоступны, пока не будет получен символ новой строки или буфер не заполнится.
- блочная буферизация: когда буфер дескриптора становится пустым, в него считывается следующий блок данных.
-
без буферизации: следующий элемент ввода считывается и возвращается. Операция
hLookAheadподразумевает, что даже для дескриптора без буферизации может потребоваться буфер размером в один символ.
Режим буферизации по умолчанию при открытии дескриптора зависит от реализации и может зависеть от объекта файловой системы, связанного с этим дескриптором. В большинстве реализаций для физических файлов обычно используется блочная буферизация, а для терминалов — построчная.
Конструкторы
| NoBuffering | буферизация отключена, если это возможно. |
| LineBuffering | построчная буферизация включена, если это возможно. |
| BlockBuffering (Maybe Int) | блочная буферизация включена, если это возможно. Размер буфера составляет |
Экземпляры
hSetBuffering :: Handle -> BufferMode -> IO () Источник
Вычисление hSetBuffering hdl mode задаёт режим буферизации дескриптора hdl при последующих операциях чтения и записи.
Если режим буферизации изменяется с BlockBuffering или LineBuffering на NoBuffering, то
- если
hdlдопускает запись, буфер сбрасывается так же, как приhFlush; - если
hdlне допускает запись, содержимое буфера отбрасывается.
Эта операция может завершиться ошибкой:
-
isPermissionError, если дескриптор уже использовался для чтения или записи, а реализация не позволяет изменить режим буферизации.
hGetBuffering :: Handle -> IO BufferMode Источник
Вычисление hGetBuffering hdl возвращает текущий режим буферизации для hdl.
hFlush :: Handle -> IO () Источник
Действие hFlush hdl приводит к немедленной передаче операционной системе всех данных, буферизованных для вывода в дескрипторе hdl.
Эта операция может завершиться ошибкой:
-
isFullError, если устройство заполнено; -
isPermissionError, если будет превышен системный лимит ресурсов. В этих обстоятельствах не определено, будут ли символы в буфере отброшены или сохранены.
Изменение позиции дескрипторов
hGetPosn :: Handle -> IO HandlePosn Источник
Вычисление hGetPosn hdl возвращает текущую позицию ввода-вывода дескриптора hdl в виде значения абстрактного типа HandlePosn.
hSetPosn :: HandlePosn -> IO () Источник
Если вызов hGetPosn hdl возвращает позицию p, то вычисление hSetPosn p устанавливает позицию hdl в то значение, которое она имела во время вызова hGetPosn.
Эта операция может завершиться ошибкой:
-
isPermissionError, если будет превышен системный лимит ресурсов.
data HandlePosn Источник
Экземпляры
| Eq HandlePosn Источник | Начиная с: base-4.1.0.0 |
Определён в GHC.Internal.IO.Handle Методы(==) :: HandlePosn -> HandlePosn -> Bool Источник (/=) :: HandlePosn -> HandlePosn -> Bool Источник | |
| Show HandlePosn Источник | Начиная с: base-4.1.0.0 |
Определён в GHC.Internal.IO.Handle МетодыshowsPrec :: Int -> HandlePosn -> ShowS Источник show :: HandlePosn -> String Источник showList :: [HandlePosn] -> ShowS Источник | |
hSeek :: Handle -> SeekMode -> Integer -> IO () Источник
Вычисление hSeek hdl mode i устанавливает позицию дескриптора hdl в зависимости от mode. Смещение i задаётся в 8-битных байтах.
Если hdl буферизуется блоками или строками, то при переходе к позиции, не находящейся в текущем буфере, сначала все элементы выходного буфера записываются на устройство, а затем входной буфер отбрасывается. Некоторые дескрипторы могут не поддерживать позиционирование (см. hIsSeekable) или поддерживать лишь часть возможных операций позиционирования (например, может быть возможен переход только в конец ленты либо к положительному смещению относительно начала или текущей позиции). Нельзя задать отрицательную позицию ввода-вывода, а для физического файла — позицию ввода-вывода за текущим концом файла.
Эта операция может завершиться ошибкой в следующих случаях:
-
isIllegalOperationError, если дескриптор не поддерживает позиционирование или не поддерживает запрошенный режим позиционирования. -
isPermissionError, если будет превышено ограничение системных ресурсов.
Режим, определяющий действие hSeek hdl mode i.
Конструкторы
| AbsoluteSeek | позиция |
| RelativeSeek | позиция |
| SeekFromEnd | позиция |
Экземпляры
hTell :: Handle -> IO Integer Источник
Вычисление hTell hdl возвращает текущую позицию дескриптора hdl в виде количества байтов от начала файла. Возвращённое значение впоследствии можно передать в hSeek, чтобы переместить дескриптор в текущую позицию.
Эта операция может завершиться ошибкой:
-
isIllegalOperationError, если дескриптор не поддерживает позиционирование.
Свойства дескриптора
hIsOpen :: Handle -> IO Bool Источник
hIsOpen hdl возвращает, открыт ли дескриптор. Если haType у hdl равно ClosedHandle или SemiClosedHandle, возвращается False, иначе — True.
hIsClosed :: Handle -> IO Bool Источник
hIsOpen hdl возвращает, закрыт ли дескриптор. Если haType у hdl равно ClosedHandle, возвращается True, иначе — False.
hIsReadable :: Handle -> IO Bool Источник
hIsReadable hdl возвращает, можно ли читать из дескриптора.
hIsWritable :: Handle -> IO Bool Источник
hIsWritable hdl возвращает, можно ли записывать в дескриптор.
hIsSeekable :: Handle -> IO Bool Источник
hIsSeekable hdl возвращает, возможно ли hSeek для указанного дескриптора.
Операции с терминалом (непереносимо: только GHC)
hIsTerminalDevice :: Handle -> IO Bool Источник
Подключён ли дескриптор к терминалу?
В Windows результат hIsTerminalDevide может вводить в заблуждение, поскольку эмуляторы терминала, не являющиеся нативными, например MinTTY, используемый в средах MSYS и Cygwin, реализованы с помощью перенаправления. Используйте System.Win32.Types.withHandleToHANDLE System.Win32.MinTTY.isMinTTYHandle, чтобы распознать такой терминал. Также рассмотрите пакет ansi-terminal для поддержки терминалов на разных платформах.
hSetEcho :: Handle -> Bool -> IO () Источник
Устанавливает состояние эхо-вывода для дескриптора, подключённого к терминалу.
hGetEcho :: Handle -> IO Bool Источник
Получает состояние эхо-вывода для дескриптора, подключённого к терминалу.
Отображение состояния дескриптора (непереносимо: только GHC)
hShow :: Handle -> IO String Источник
hShow выполняется в монаде IO и выводит более подробную информацию, чем (чистый) экземпляр Show для Handle.
Текстовый ввод и вывод
Текстовый ввод
hWaitForInput :: Handle -> Int -> IO Bool Источник
Вычисление hWaitForInput hdl t ожидает появления входных данных в дескрипторе hdl. Оно возвращает True, как только входные данные становятся доступны в hdl, или False, если данные не появляются в течение t миллисекунд. Обратите внимание, что hWaitForInput ожидает появления одного или нескольких полных символов, поэтому выполняет декодирование и, следовательно, может завершиться ошибкой декодирования.
Если t меньше нуля, hWaitForInput ожидает бесконечно.
Эта операция может завершиться ошибкой:
-
isEOFError, если достигнут конец файла. - ошибка декодирования, если входные данные начинаются с недопустимой последовательности байтов в кодировке этого дескриптора.
ПРИМЕЧАНИЕ для пользователей GHC: если не использовать флаг -threaded, вызов hWaitForInput hdl t, где t >= 0, будет блокировать все остальные потоки Haskell на время выполнения вызова. В этом отношении он ведёт себя как иностранный вызов safe.
hReady :: Handle -> IO Bool Источник
Вычисление hReady hdl указывает, доступен ли хотя бы один элемент для чтения из дескриптора hdl.
Эта операция может завершиться ошибкой:
-
isEOFError, если достигнут конец файла.
hGetChar :: Handle -> IO Char Источник
Вычисление hGetChar hdl считывает символ из файла или канала, которым управляет hdl, и блокируется до появления символа.
Эта операция может завершиться ошибкой:
-
isEOFError, если достигнут конец файла.
hGetLine :: Handle -> IO String Источник
Вычисление hGetLine hdl считывает строку из файла или канала, которым управляет hdl. hGetLine не включает символ новой строки в результат.
Строки разделяются символом новой строки, заданным с помощью hSetNewlineMode или по умолчанию — nativeNewline. Считанные символы новой строки не включаются в результат.
Если hGetLine встречает конец файла во время чтения строки, то он считается её окончанием, и возвращается (частичная) строка.
Эта операция может завершиться ошибкой:
-
isEOFError, если конец файла встречен при чтении первого символа строки.
Примеры
>>> withFile "/home/user/foo" ReadMode hGetLine >>= putStrLn this is the first line of the file :O
>>> withFile "/home/user/bar" ReadMode (replicateM 3 . hGetLine) ["this is the first line","this is the second line","this is the third line"]
hLookAhead :: Handle -> IO Char Источник
Вычисление hLookAhead возвращает следующий символ из дескриптора, не удаляя его из входного буфера, и блокируется до появления символа.
Эта операция может завершиться ошибкой:
-
isEOFError, если достигнут конец файла.
hGetContents :: Handle -> IO String Источник
Вычисление hGetContents hdl возвращает список символов, соответствующих непрочитанной части канала или файла, которым управляет hdl, переводя его в промежуточное состояние — полузакрытое. В этом состоянии hdl фактически закрыт, но элементы считываются из hdl по мере необходимости и накапливаются в специальном списке, возвращаемом hGetContents hdl.
Любая операция, завершающаяся ошибкой из-за закрытого дескриптора, также завершается ошибкой, если дескриптор полузакрыт. Единственное исключение — hClose. Полузакрытый дескриптор становится закрытым:
- если к нему применяется
hClose; - если при чтении элемента из дескриптора возникает ошибка ввода-вывода;
- или после чтения всего содержимого дескриптора.
После закрытия полузакрытого дескриптора содержимое связанного с ним списка фиксируется. Содержимое этого окончательного списка определено лишь частично: он будет содержать как минимум все элементы потока, вычисленные до закрытия дескриптора.
Все ошибки ввода-вывода, возникающие, когда дескриптор полузакрыт, просто отбрасываются.
Эта операция может завершиться ошибкой:
-
isEOFError, если достигнут конец файла.
hGetContents' :: Handle -> IO String Источник
Операция hGetContents' считывает все входные данные из указанного дескриптора, прежде чем вернуть их в виде String и закрыть дескриптор.
Это строгая версия hGetContents
Начиная с: base-4.15.0.0
Текстовый вывод
Вычисление hPutChar hdl ch записывает символ ch в файл или канал, управляемый hdl. Символы могут буферизоваться, если для hdl включена буферизация.
Эта операция может завершиться ошибкой в следующих случаях:
-
isFullError, если устройство заполнено. -
isPermissionError, если будет превышен другой лимит системных ресурсов.
hPutStr :: Handle -> String -> IO () Источник
Вычисление hPutStr hdl s записывает строку s в файл или канал, управляемый hdl.
Обратите внимание: hPutStr не является безопасной при конкурентном выполнении, если BufferMode у hdl не установлено в LineBuffering или BlockBuffering:
>>> let f = forkIO . hPutStr stdout >>> in do hSetBuffering stdout NoBuffering; f "This is a longer string"; f ":D"; f "Hello Haskell"; pure () This: HDiesl lao lHoansgkeerl lstring
>>> let f = forkIO . hPutStr stdout >>> in do hSetBuffering stdout LineBuffering; f "This is a longer string"; f ":D"; f "Hello Haskell"; pure () This is a longer string:DHello Haskell
Эта операция может завершиться ошибкой в следующих случаях:
-
isFullError, если устройство заполнено. -
isPermissionError, если будет превышен другой лимит системных ресурсов.
hPutStrLn :: Handle -> String -> IO () Источник
То же, что и hPutStr, но с добавлением символа новой строки.
Эта операция может завершиться с теми же ошибками и имеет те же проблемы с конкурентным выполнением, что и hPutStr!
hPrint :: Show a => Handle -> a -> IO () Источник
Вычисление hPrint hdl t записывает в файл или канал, управляемый hdl, строковое представление t, полученное с помощью функции show, и добавляет символ новой строки.
Эта операция может завершиться с теми же ошибками, что и hPutStrLn
Примеры
>>> hPrint stdout [1,2,3] [1,2,3]
>>> hPrint stdin [4,5,6] *** Exception: <stdin>: hPutStr: illegal operation (handle is not open for writing)
Особые случаи для стандартного ввода и вывода
Эти функции также экспортируются модулем Prelude.
interact :: (String -> String) -> IO () Источник
interact f считывает весь ввод из stdin и применяет к нему f. Полученная строка записывается на устройство stdout.
Обратите внимание, что эта операция является ленивой, поэтому вывод может производиться ещё до того, как будет считан весь ввод.
Эта операция может завершиться с теми же ошибками, что и getContents и putStr.
Примеры
>>> interact (\str -> str ++ str) > hi :) hi :) > ^D hi :)
>>> interact (const ":D") :D
>>> interact (show . words) > hello world! > I hope you have a great day > ^D ["hello","world!","I","hope","you","have","a","great","day"]
putChar :: Char -> IO () Источник
Записывает символ на устройство стандартного вывода
putChar реализована как hPutChar stdout.
Эта операция может завершиться с теми же ошибками, что и hPutChar.
Примеры
Обратите внимание, что следующий код не добавляет символ новой строки.
>>> putChar 'x' x
>>> putChar '\0042' *
putStr :: String -> IO () Источник
Записывает строку на устройство стандартного вывода
putStr реализована как hPutStr stdout.
Эта операция может завершиться с теми же ошибками и имеет те же проблемы с конкурентным выполнением, что и hPutStr!
Примеры
Обратите внимание, что следующий код не добавляет символ новой строки.
>>> putStr "Hello, World!" Hello, World!
>>> putStr "\0052\0042\0050" 4*2
putStrLn :: String -> IO () Источник
То же, что и putStr, но с добавлением символа новой строки.
Эта операция может завершиться с теми же ошибками и имеет те же проблемы с конкурентным выполнением, что и hPutStr!
print :: Show a => a -> IO () Источник
Функция print выводит значение любого печатаемого типа на устройство стандартного вывода. Печатаемые типы — это типы, являющиеся экземплярами класса Show; print преобразует значения в строки для вывода с помощью операции show и добавляет символ новой строки.
print реализована как putStrLn . show
Эта операция может завершиться с теми же ошибками и имеет те же проблемы с конкурентным выполнением, что и hPutStr!
Примеры
>>> print [1, 2, 3] [1,2,3]
Будьте осторожны при использовании print для вывода строк: при этом будет вызвана show, и строки будут напечатаны в кавычках, а символы, не относящиеся к ASCII, будут экранированы.
>>> print "λ :D" "\995 :D"
Программу для вывода первых 8 целых чисел и соответствующих им степеней двойки можно записать так:
>>> print [(n, 2^n) | n <- [0..8]] [(0,1),(1,2),(2,4),(3,8),(4,16),(5,32),(6,64),(7,128),(8,256)]
Считывает один символ с устройства стандартного ввода.
getChar реализована как hGetChar stdin.
Эта операция может завершиться с теми же ошибками, что и hGetChar.
Примеры
>>> getChar a'a'
>>> getChar > '\n'
Считывает строку с устройства стандартного ввода.
getLine реализована как hGetLine stdin.
Эта операция может завершиться с теми же ошибками, что и hGetLine.
Примеры
>>> getLine > Hello World! "Hello World!"
>>> getLine > ""
getContents :: IO String Источник
Операция getContents возвращает весь пользовательский ввод в виде одной строки, которая считывается лениво по мере необходимости.
getContents реализована как hGetContents stdin.
Эта операция может завершиться с теми же ошибками, что и hGetContents.
Примеры
>>> getContents >>= putStr > aaabbbccc :D aaabbbccc :D > I hope you have a great day I hope you have a great day > ^D
>>> getContents >>= print . length > abc > <3 > def ^D 11
getContents' :: IO String Источник
Операция getContents' возвращает весь пользовательский ввод в виде одной строки, которая полностью считывается до возврата результата
getContents' реализована как hGetContents' stdin.
Эта операция может завершиться с теми же ошибками, что и hGetContents'.
Примеры
>>> getContents' >>= putStr > aaabbbccc :D > I hope you have a great day aaabbbccc :D I hope you have a great day
>>> getContents' >>= print . length > abc > <3 > def ^D 11
Начиная с: base-4.15.0.0
readIO :: Read a => String -> IO a Источник
Функция readIO похожа на read, за исключением того, что при ошибке разбора она сигнализирует о ней в монаде IO, а не завершает программу.
Эта операция может завершиться ошибкой в следующих случаях:
-
isUserError, если разбор не является однозначным.
Примеры
>>> fmap (+ 1) (readIO "1") 2
>>> readIO "not quite ()" :: IO () *** Exception: user error (Prelude.readIO: no parse)
readLn :: Read a => IO a Источник
Функция readLn объединяет getLine и readIO.
Эта операция может завершиться с теми же ошибками, что и getLine и readIO.
Примеры
>>> fmap (+ 5) readLn > 25 30
>>> readLn :: IO String > this is not a string literal *** Exception: user error (Prelude.readIO: no parse)
Двоичный ввод и вывод
withBinaryFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r Источник
Вычисление withBinaryFile path mode action открывает двоичный файл и запускает action с полученным дескриптором, после чего закрывает двоичный файл.
Это отличается от withFile тем, что здесь не используется кодировка файла.
Файл будет закрыт, даже если во время выполнения action возникнет исключение. Поэтому withBinaryFile path mode act предпочтительнее, чем
openBinaryFile path mode >>= (\hdl -> act hdl >>= hClose hdl)
См. также: bracket
Аргументы
| :: FilePath | Путь к двоичному файлу, который необходимо открыть |
| -> IOMode | Режим, в котором следует открыть двоичный файл |
| -> IO Handle |
Вычисление openBinaryFile path mode возвращает дескриптор файла, который можно использовать для взаимодействия с двоичным файлом.
Это отличается от openFile тем, что здесь не используется кодировка файла.
hSetBinaryMode :: Handle -> Bool -> IO () Источник
Выбирает двоичный режим (True) или текстовый режим (False) для открытого дескриптора. (См. также openBinaryFile.)
Это даёт тот же эффект, что и вызов hSetEncoding с char8 вместе с hSetNewlineMode с noNewlineTranslation.
hPutBuf :: Handle -> Ptr a -> Int -> IO () Источник
hPutBuf hdl buf count записывает count 8-битовых байтов из буфера buf в дескриптор hdl. Возвращает ().
hPutBuf игнорирует текстовую кодировку, применяемую к Handle, и записывает байты непосредственно в соответствующий файл или устройство.
hPutBuf игнорирует действующие TextEncoding и NewlineMode для Handle и записывает байты напрямую.
Эта операция может завершиться ошибкой:
-
ResourceVanished, если дескриптор является каналом или сокетом и читающая сторона закрыта. (Если используется POSIX-система и программа не запросила игнорирование SIGPIPE, вместо этого может быть доставлен SIGPIPE, действие по умолчанию для которого — завершение программы.)
hGetBuf :: Handle -> Ptr a -> Int -> IO Int Источник
hGetBuf hdl buf count считывает данные из дескриптора hdl в буфер buf, пока не будет достигнут конец файла (EOF) или не будут считаны count 8-битовых байтов. Возвращает количество фактически считанных байтов. Оно может быть равно нулю, если конец файла был достигнут до считывания каких-либо данных (или если count равно нулю).
hGetBuf никогда не вызывает исключение EOF, а вместо этого возвращает значение меньше count.
Если дескриптор является каналом или сокетом и записывающая сторона закрыта, hGetBuf будет вести себя так, как если бы был достигнут конец файла.
hGetBuf игнорирует действующие TextEncoding и NewlineMode для Handle и считывает байты напрямую.
hGetBufSome :: Handle -> Ptr a -> Int -> IO Int Источник
hGetBufSome hdl buf count считывает данные из дескриптора hdl в буфер buf. Если данные доступны для чтения, hGetBufSome возвращает их немедленно; блокировка происходит только при отсутствии данных для чтения.
Возвращает количество фактически считанных байтов. Оно может быть равно нулю, если конец файла был достигнут до считывания каких-либо данных (или если count равно нулю).
hGetBufSome никогда не вызывает исключение EOF, а вместо этого возвращает значение меньше count.
Если дескриптор является каналом или сокетом и записывающая сторона закрыта, hGetBufSome будет вести себя так, как если бы был достигнут конец файла.
hGetBufSome игнорирует действующие TextEncoding и NewlineMode для Handle и считывает байты напрямую.
hPutBufNonBlocking :: Handle -> Ptr a -> Int -> IO Int Источник
hGetBufNonBlocking :: Handle -> Ptr a -> Int -> IO Int Источник
hGetBufNonBlocking hdl buf count считывает данные из дескриптора hdl в буфер buf, пока не будет достигнут конец файла (EOF), не будут считаны count 8-битовых байтов или не останется данных, доступных для немедленного чтения.
hGetBufNonBlocking идентична hGetBuf, но никогда не блокирует выполнение в ожидании появления данных, а возвращает только те данные, которые доступны. Чтобы дождаться поступления данных перед вызовом hGetBufNonBlocking, используйте hWaitForInput.
Если дескриптор является каналом или сокетом и записывающая сторона закрыта, hGetBufNonBlocking будет вести себя так, как если бы был достигнут конец файла.
hGetBufNonBlocking игнорирует действующие TextEncoding и NewlineMode для Handle и считывает байты напрямую.
ПРИМЕЧАНИЕ: в Windows эта функция работает некорректно; она ведёт себя так же, как hGetBuf.
Временные файлы
Аргументы
| :: FilePath | Каталог, в котором нужно создать файл |
| -> String | Шаблон имени файла. Если шаблон — "foo.ext", созданный файл будет называться "fooXXX.ext", где XXX — некоторое случайное число. Обратите внимание: шаблон не должен содержать символы-разделители пути. В Windows префикс шаблона может быть усечён до 3 символов, например "foobar.ext" превратится в "fooXXX.ext". |
| -> IO (FilePath, Handle) |
Функция создаёт временный файл в режиме чтения и записи. Созданный файл не удаляется автоматически, поэтому его нужно удалить вручную.
Файл создаётся с разрешениями, позволяющими читать и записывать его только текущему пользователю.
За некоторыми исключениями (см. ниже), файл создаётся безопасным образом: злоумышленник не должен иметь возможности заставить openTempFile перезаписать другой файл в файловой системе с использованием ваших учётных данных, поместив символические ссылки (в Unix) туда, где должен быть создан временный файл. В Unix для предотвращения этой атаки используются флаги O_CREAT и O_EXCL, однако обратите внимание, что O_EXCL иногда не поддерживается файловыми системами NFS. Поэтому, если вы полагаетесь на это поведение, лучше использовать только локальные файловые системы.
openBinaryTempFile :: FilePath -> String -> IO (FilePath, Handle) Источник
Как openTempFile, но открывает файл в двоичном режиме. Дополнительные замечания см. в openBinaryFile.
openTempFileWithDefaultPermissions :: FilePath -> String -> IO (FilePath, Handle) Источник
Как openTempFile, но использует разрешения по умолчанию для файлов
openBinaryTempFileWithDefaultPermissions :: FilePath -> String -> IO (FilePath, Handle) Источник
Как openBinaryTempFile, но использует разрешения по умолчанию для файлов
Кодирование и декодирование Unicode
С текстовым Handle связана TextEncoding, которая используется для декодирования байтов в символы Unicode при чтении и кодирования символов Unicode в байты при записи.
По умолчанию TextEncoding совпадает с кодировкой по умолчанию в вашей системе; она также доступна как localeEncoding. (Примечание GHC: в Windows в настоящее время не поддерживаются двухбайтовые кодировки; если кодовая страница консоли не поддерживается, то localeEncoding будет равна latin1.)
Ошибки кодирования и декодирования всегда обнаруживаются и сообщаются, кроме случаев ленивого ввода-вывода (hGetContents, getContents и readFile), когда ошибка декодирования лишь приводит к завершению потока символов, как и другие ошибки ввода-вывода.
hSetEncoding :: Handle -> TextEncoding -> IO () Источник
Действие hSetEncoding hdl encoding меняет текстовую кодировку дескриптора hdl на encoding. Кодировка по умолчанию при создании Handle — localeEncoding, то есть кодировка по умолчанию для текущей локали.
Чтобы создать Handle вообще без кодировки, используйте openBinaryFile. Чтобы отключить дальнейшее кодирование или декодирование для существующего Handle, используйте hSetBinaryMode.
Для смены кодировки hSetEncoding может потребоваться сбросить буферизованные данные.
hGetEncoding :: Handle -> IO (Maybe TextEncoding) Источник
Возвращает текущую TextEncoding для указанного Handle или Nothing, если Handle находится в двоичном режиме.
Обратите внимание, что TextEncoding не сохраняет сведения о состоянии кодировщика/декодировщика, используемого для этого Handle. Например, если используется кодировка UTF-16, то применение hGetEncoding и hSetEncoding для сохранения и восстановления кодировки может привести к записи в файл дополнительной метки порядка байтов.
Кодировки Unicode
data TextEncoding Источник
TextEncoding — это спецификация схемы преобразования между последовательностями байтов и последовательностями символов Unicode.
Например, UTF-8 — это кодировка, представляющая символы Unicode в виде последовательности байтов. TextEncoding для UTF-8 — это utf8.
Экземпляры
| Show TextEncoding Источник | Начиная с: base-4.3.0.0 |
Определено в GHC.Internal.IO.Encoding.Types МетодыshowsPrec :: Int -> TextEncoding -> ShowS Источник show :: TextEncoding -> String Источник showList :: [TextEncoding] -> ShowS Источник | |
latin1 :: TextEncoding Источник
Кодировка Latin1 (ISO8859-1). Эта кодировка напрямую сопоставляет байты первым 256 кодовым точкам Unicode и поэтому не является полной кодировкой Unicode. Попытка записать символ с кодовой точкой выше '\255' в Handle с использованием кодировки latin1 приведёт к ошибке.
Кодировка Unicode UTF-8
utf8_bom :: TextEncoding Источник
Кодировка Unicode UTF-8 с меткой порядка байтов (BOM; последовательность байтов 0xEF 0xBB 0xBF). Эта кодировка работает как utf8, за исключением того, что при чтении последовательность BOM игнорируется в начале потока, а при записи она добавляется в начало.
Метка порядка байтов совершенно не нужна в UTF-8, но иногда используется для определения кодировки файла.
utf16 :: TextEncoding Источник
Кодировка Unicode UTF-16 (для указания порядка байтов следует использовать метку порядка байтов).
utf16le :: TextEncoding Источник
Кодировка Unicode UTF-16 (порядок байтов от младшего к старшему)
utf16be :: TextEncoding Источник
Кодировка Unicode UTF-16 (порядок байтов от старшего к младшему)
utf32 :: TextEncoding Источник
Кодировка Unicode UTF-32 (для указания порядка байтов следует использовать метку порядка байтов).
utf32le :: TextEncoding Источник
Кодировка Unicode UTF-32 (порядок байтов от младшего к старшему)
utf32be :: TextEncoding Источник
Кодировка Unicode UTF-32 (порядок байтов от старшего к младшему)
localeEncoding :: TextEncoding Источник
Кодировка текущей локали.
Это исходная кодировка локали: если впоследствии она была изменена с помощью setLocaleEncoding, это значение не будет отражать такое изменение.
char8 :: TextEncoding Источник
Кодировка, в которой кодовые точки Unicode преобразуются в байты путём взятия остатка от деления кодовой точки на 256. При декодировании байты напрямую преобразуются в соответствующие кодовые точки.
Эта кодировка никогда не приводит к ошибке ни в одном из направлений. Однако кодирование отбрасывает информацию, поэтому последовательность «кодирование, затем декодирование» не является тождественным преобразованием.
Начиная с: base-4.4.0.0
mkTextEncoding :: String -> IO TextEncoding Источник
Найти именованную кодировку Unicode. Может завершиться ошибкой
-
isDoesNotExistError, если кодировка неизвестна
Набор известных кодировок зависит от системы, но включает как минимум:
UTF-8
-
UTF-16,UTF-16BE,UTF-16LE -
UTF-32,UTF-32BE,UTF-32LE
Для указания способа обработки недопустимых символов предусмотрен дополнительный синтаксис (заимствованный из GNU iconv):
- суффикс
//IGNORE, напримерUTF-8//IGNORE, приводит к игнорированию всех недопустимых последовательностей при чтении, а при записи отбрасываются все кодовые точки, не имеющие представления в целевой кодировке. - суффикс
//TRANSLITзадаёт использование символа замены для недопустимых последовательностей или кодовых точек. - суффикс
//ROUNDTRIPвключает механизм экранирования в стиле PEP383, представляющий любые недопустимые байты во входных данных как кодовые точки Unicode (в частности, как одиночные суррогаты, обычно недопустимые в UTF-32). При записи эти специальные кодовые точки обнаруживаются и преобразуются обратно в соответствующие исходные байты.
Теоретически этот механизм позволяет выполнить цикл чтения и записи произвольных данных через String без потери данных. На практике следует учитывать два ограничения:
- Это может сработать только для кодировки, являющейся надмножеством ASCII, поскольку из соображений безопасности мы отказываемся экранировать байты со значениями меньше 128. Многие интересующие нас кодировки являются надмножествами ASCII (в частности, можно считать, что кодировка локали является надмножеством ASCII), но многие другие (например, UTF-16) таковыми не являются.
- Если базовая кодировка сама по себе не обеспечивает обратимость преобразования, этот механизм может дать сбой. Обратимыми являются кодировки с инъективным отображением в Unicode. Этому критерию соответствуют почти все кодировки, но не все. В частности, Shift-JIS (CP932) и Big5 содержат несколько разных кодировок одной и той же кодовой точки Unicode.
В Windows доступ к поддерживаемым кодовым страницам можно получить с префиксом CP; например, "CP1250".
Преобразование символов новой строки
В Haskell символ новой строки всегда представлен символом '\n'. Однако в файлах и внешних потоках символов новая строка может быть представлена другой последовательностью символов, например '\r\n'.
С текстовым Handle связан NewlineMode, определяющий способ преобразования символов новой строки. NewlineMode отдельно задаёт преобразование при вводе и выводе, поэтому, например, можно преобразовывать '\r\n' в '\n' при вводе, но оставлять символы новой строки как '\n' при выводе.
По умолчанию для Handle используется NewlineMode nativeNewlineMode: в системах Unix преобразование не выполняется, а в Windows '\r\n' преобразуется в '\n' и обратно.
Для Handle в двоичном режиме преобразование символов новой строки не выполняется.
hSetNewlineMode :: Handle -> NewlineMode -> IO () Источник
Задать NewlineMode для указанного Handle. Сначала записываются все буферизованные данные.
Представление символа новой строки во внешнем файле или потоке.
Экземпляры
| Eq Newline Источник | Начиная с: base-4.2.0.0 |
| Ord Newline Источник | Начиная с: base-4.3.0.0 |
Определено в GHC.Internal.IO.Handle.Types | |
| Read Newline Источник | Начиная с: base-4.3.0.0 |
| Show Newline Источник | Начиная с: base-4.3.0.0 |
nativeNewline :: Newline Источник
Представление символа перевода строки, используемое на текущей платформе: LF в системах Unix, CRLF в Windows.
data NewlineMode Источник
Задает преобразование символов перевода строки (если оно выполняется) между внутренними строками и внешним файлом или потоком. Считается, что строки Haskell представляют символы перевода строки с помощью символа '\n'; режим перевода строк задает способ преобразования '\n' при выводе и то, во что преобразовывать входные данные вместо '\n'.
Конструкторы
| NewlineMode | |
Экземпляры
noNewlineTranslation :: NewlineMode Источник
Не выполнять преобразование символов новой строки.
noNewlineTranslation = NewlineMode { inputNL = LF, outputNL = LF }
universalNewlineMode :: NewlineMode Источник
При чтении преобразовывать '\r\n' в '\n', а при записи — '\n' в используемое в системе представление символа новой строки. Этот режим можно использовать на любой платформе; он работает с текстовыми файлами, в которых используются любые соглашения о символах новой строки. Недостаток в том, что readFile >>= writeFile может привести к изменению файла.
universalNewlineMode = NewlineMode { inputNL = CRLF,
outputNL = nativeNewline }
nativeNewlineMode :: NewlineMode Источник
Использовать системное представление символа новой строки как при чтении, так и при записи.
nativeNewlineMode = NewlineMode { inputNL = nativeNewline
outputNL = nativeNewline }
© The University of Glasgow and others
Licensed under a BSD-style license (see top of the page).
https://downloads.haskell.org/~ghc/9.14.1/docs/libraries/base-4.22.0.0-66f8/System-IO.html