System.IO
| Авторские права | (c) Университет Глазго 2001 |
|---|---|
| Лицензия | BSD (см. файл libraries/base/LICENSE) |
| Поддержка | libraries@haskell.org |
| Стабильность | стабильная |
| Переносимость | переносимая |
| Safe Haskell | Безопасная |
| Язык | Haskell2010 |
Описание
Стандартный API ввода-вывода.
Примеры
Примечание: Некоторые примеры в этом модуле не работают "как есть" в ghci. Это потому, что использование stdin в сочетании с ленивым IO не работает хорошо в интерактивном режиме.
Строки, начинающиеся с > обозначают stdin и ^D сигнализируют об окончании файла.
Пример
ghci> foo > input output > input^D output
Монад IO
Значение типа IO a представляет собой вычисление, которое при выполнении выполняет некоторое ввод-вывод перед возвращением значения типа a.
Существует только один способ "выполнения" действия ввода-вывода: привязать его к Main.main в вашей программе. Когда ваша программа выполняется, ввод-вывод будет выполнен. Невозможно выполнить ввод-вывод из произвольной функции, если эта функция сама не находится в IO монаде и не вызывается в какой-то момент, прямо или косвенно, из Main.main.
IO — это монада, поэтому действия в IO могут быть объединены с помощью синтаксиса do или операций >> и >>= из класса Monad.
Примеры
| Alternative IO Source |
Возвращает результат первого действия, которое не вызвало исключение. Since: base-4.9.0.0 |
| Applicative IO Source | Since: base-2.1 |
| Functor IO Source | Since: base-2.1 |
| Monad IO Source | Since: base-2.1 |
| MonadPlus IO Source |
Возвращает результат первого действия, которое не вызвало исключение. Since: base-4.9.0.0 |
| MonadFail IO Source | Since: base-4.9.0.0 |
Определено в GHC.Internal.Control.Monad.Fail | |
| MonadFix IO Source | Since: base-2.1 |
Определено в GHC.Internal.Control.Monad.Fix | |
| 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 Исходный код | |
Определено в GHC.Internal.TH.Syntax | |
Краткое описание методовqNewName :: String -> IO Name Source qReport :: Bool -> String -> IO () Source qRecover :: IO a -> IO a -> IO a Source qLookupName :: Bool -> String -> IO (Maybe Name) Source qReify :: Name -> IO Info Source qReifyFixity :: Name -> IO (Maybe Fixity) Source qReifyType :: Name -> IO Type Source qReifyInstances :: Name -> [Type] -> IO [Dec] Source qReifyRoles :: Name -> IO [Role] Source qReifyAnnotations :: Data a => AnnLookup -> IO [a] Source qReifyModule :: Module -> IO ModuleInfo Source qReifyConStrictness :: Name -> IO [DecidedStrictness] Source qGetPackageRoot :: IO FilePath Source qAddDependentFile :: FilePath -> IO () Source qAddTempFile :: String -> IO FilePath Source qAddTopDecls :: [Dec] -> IO () Source qAddForeignFilePath :: ForeignSrcLang -> String -> IO () Source qAddModFinalizer :: Q () -> IO () Source qAddCorePlugin :: String -> IO () Source |
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, чье точное значение зависит от операционной системы. Файлы могут быть открыты, что возвращает дескриптор, который затем можно использовать для работы с содержимым этого файла.
data Дескриптор Исходный код
Haskell определяет операции чтения и записи символов из файлов и в файлы, представленные значениями типа Handle. Каждое значение этого типа является дескриптором: записью, используемой системой выполнения Haskell для управления вводом-выводом с объектами файловой системы. Дескриптор имеет по крайней мере следующие свойства:
- является ли он дескриптором ввода, вывода или обоих;
- является ли он открытым, закрытым или полузакрытым;
- является ли объект позиционируемым;
- выключен ли буферинг или включен по строкам или блокам;
- буфер (длина которого может быть нулевой).
Большинство дескрипторов также имеют текущую позицию ввода-вывода, указывающую, где произойдёт следующая операция ввода или вывода. Дескриптор является читаемым, если он управляет только вводом или и вводом, и выводом; аналогично, он является записываемым, если он управляет только выводом или и вводом, и выводом. Дескриптор открыт при первом выделении. После закрытия он больше не может использоваться ни для ввода, ни для вывода, хотя реализация не может повторно использовать его хранилище, пока к нему остаются ссылки. Дескрипторы находятся в классах Show и Eq. Строка, полученная при отображении дескриптора, зависит от системы; она должна содержать достаточно информации для идентификации дескриптора в отладке. Дескриптор равен только самому себе согласно ==; не предпринимается попытка сравнить внутреннее состояние различных дескрипторов для равенства.
Примеры
| Show Handle Исходный код | С момента: base-4.1.0.0 |
Определено в GHC.Internal.IO.Handle.Types МетодыshowsPrec :: Int -> Handle -> ShowS Исходный код show :: Handle -> String Исходный код showList :: [Handle] -> ShowS Исходный код | |
| Eq Handle Исходный код | С момента: base-4.1.0.0 |
Определено в GHC.Internal.IO.Handle.Types | |
Примечание 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.
data IOMode Исходный код
См. openFile
Конструкторы
| ReadMode | |
| WriteMode | |
| AppendMode | |
| ReadWriteMode |
Примеры
| Ord IOMode Источник | С момента: base-4.2.0.0 |
Определено в GHC.Internal.IO.IOMode | |
Закрытие файлов
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 () Source
hSetFileSize hdl size обрезает физический файл с дескриптором hdl до size байт.
Обнаружение конца входных данных
hIsEOF :: Handle -> IO Bool Source
Для удобочитаемого дескриптора hdl, hIsEOF hdl возвращает значение True, если из hdl больше данных получить нельзя, или для физического файла, если текущая позиция ввода/вывода равна длине файла. В противном случае, возвращается False.
ПРИМЕЧАНИЕ: hIsEOF может заблокироваться, так как ему нужно попытаться прочитать из потока, чтобы определить, есть ли больше данных для чтения.
Вычисление isEOF идентично hIsEOF, за исключением того, что оно работает только с stdin.
Операции буферизации
data BufferMode Source
Поддерживаются три вида буферизации: строчная, блочная или отсутствие буферизации. Эти режимы оказывают следующие эффекты. Для вывода элементы записываются или сбрасываются из внутреннего буфера в соответствии с режимом буферизации:
-
строчная буферизация: весь буфер вывода сбрасывается всякий раз, когда выводится символ новой строки, буфер переполняется, выводится
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 Source
Вычисление hGetPosn hdl возвращает текущую позицию ввода-вывода hdl как значение абстрактного типа HandlePosn.
hSetPosn :: HandlePosn -> IO () Source
Если вызов hGetPosn hdl возвращает позицию p, то вычисление hSetPosn p устанавливает позицию hdl на позицию, которую она занимала в момент вызова hGetPosn.
Данная операция может завершиться неудачей из-за:
-
isPermissionErrorесли бы было превышено ограничение системных ресурсов.
data HandlePosn Source
Примеры
| Show HandlePosn Source | С версии: base-4.1.0.0 |
Определено в GHC.Internal.IO.Handle МетодыshowsPrec :: Int -> HandlePosn -> ShowS Source show :: HandlePosn -> String Source showList :: [HandlePosn] -> ShowS Source | |
| Eq HandlePosn Source | С версии: base-4.1.0.0 |
Определено в GHC.Internal.IO.Handle Методы(==) :: HandlePosn -> HandlePosn -> Bool Source (/=) :: HandlePosn -> HandlePosn -> Bool Source | |
hSeek :: Handle -> SeekMode -> Integer -> IO () Source
Вычисление hSeek hdl mode i устанавливает позицию дескриптора hdl в зависимости от mode. Смещение i задаётся в байтах по 8 бит.
Если hdl является блочно- или пословно-буферизованным, то переход к позиции, которая не находится в текущем буфере, сначала приведёт к записи всех элементов в выходном буфере на устройство, а затем к удалению входного буфера. Некоторые дескрипторы могут не поддерживать поиск (см. hIsSeekable), или поддерживать только подмножество возможных операций позиционирования (например, возможно только перемещение к концу ленты или к смещению от начала или текущей позиции). Невозможно установить отрицательную позицию ввода-вывода или, в случае физического файла, позицию ввода-вывода, превышающую текущий конец файла.
Данная операция может завершиться неудачей из-за:
-
isIllegalOperationErrorесли дескриптор не поддерживает поиск или не поддерживает запрашиваемый режим поиска. -
isPermissionErrorесли бы было превышено ограничение системных ресурсов.
Режим, который определяет действие hSeek hdl mode i.
Конструкторы
| AbsoluteSeek | позиция |
| RelativeSeek | позиция |
| SeekFromEnd | позиция |
Примеры
| Ord SeekMode Источник | С момента: base-4.2.0.0 |
Определено в GHC.Internal.IO.Device | |
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 hdl t ожидает, пока входные данные не появятся в обработчике hdl. Оно возвращает True как только входные данные появятся в hdl, или False если входные данные не появятся в течение t миллисекунд. Обратите внимание, что hWaitForInput ожидает, пока будут доступны один или несколько полных символов, что означает, что ему необходимо выполнить декодирование, и поэтому он может завершиться с ошибкой декодирования.
Если t меньше нуля, то hWaitForInput ожидает неопределённо долго.
Данная операция может завершиться ошибкой:
-
isEOFErrorесли достигнут конец файла. - с ошибкой декодирования, если входные данные начинаются с недопустимой последовательности байтов в кодировке этого обработчика.
ПРИМЕЧАНИЕ для пользователей GHC: если вы не используете флаг -threaded, hWaitForInput hdl t где t >= 0 будет блокировать все другие потоки Haskell в течение всего времени вызова. Он ведёт себя как вызов safe внешней функции в этом отношении.
hReady :: Handle -> IO Bool Source
Вычисление hReady hdl указывает, доступна ли хотя бы одна запись для ввода из обработчика hdl.
Данная операция может завершиться ошибкой:
-
isEOFErrorесли достигнут конец файла.
hGetChar :: Handle -> IO Char Source
Вычисление hGetChar hdl считывает символ из файла или канала, управляемого hdl, блокируя до тех пор, пока символ не станет доступным.
Данная операция может завершиться ошибкой:
-
isEOFErrorесли достигнут конец файла.
hGetLine :: Handle -> IO String Source
Вычисление 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 Source
Вычисление hLookAhead возвращает следующий символ из обработчика без удаления его из буфера ввода, блокируя до тех пор, пока символ не станет доступным.
Данная операция может завершиться ошибкой:
-
isEOFErrorесли достигнут конец файла.
hGetContents :: Handle -> IO String Source
Вычисление hGetContents hdl возвращает список символов, соответствующих непрочитанной части канала или файла, управляемого hdl, который переводится в промежуточное состояние, полузакрытый. В этом состоянии hdl фактически закрыт, но элементы считываются из hdl по запросу и накапливаются в специальном списке, возвращаемом hGetContents hdl.
Любая операция, которая завершается ошибкой из-за закрытия обработчика, также завершается ошибкой, если обработчик полузакрыт. Исключением является hClose. Полузакрытый обработчик становится закрытым:
- если к нему применяется
hClose; - если возникает ошибка ввода-вывода при чтении элемента из обработчика;
- или после того, как весь контент обработчика был прочитан.
После того, как полузакрытый обработчик становится закрытым, содержимое связанного списка становится фиксированным. Содержимое этого конечного списка частично определено: оно будет содержать по крайней мере все элементы потока, которые были вычислены до того, как обработчик стал закрытым.
Любые ошибки ввода-вывода, возникшие во время работы с полузакрытым обработчиком, просто отбрасываются.
Данная операция может завершиться ошибкой:
-
isEOFErrorесли достигнут конец файла.
hGetContents' :: Handle -> IO String Source
Операция hGetContents' считывает весь ввод из заданного обработчика, прежде чем вернуть его как String и закрыть обработчик.
Это строгая версия hGetContents
С версии: base-4.15.0.0
Вывод текста
hPutChar :: Handle -> Char -> IO () Source
Вычисление hPutChar hdl ch записывает символ ch в файл или канал, управляемый hdl. Символы могут быть буферизованы, если буферизация включена для hdl.
Данная операция может завершиться ошибкой:
-
isFullErrorесли устройство заполнено. -
isPermissionErrorесли будет превышен другой системный лимит ресурсов.
hPutStr :: Handle -> String -> IO () Source
Вычисление 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 () Source
То же, что и hPutStr, но добавляет символ перевода строки.
Данная операция может завершиться теми же ошибками и имеет те же проблемы с многопоточностью, что и hPutStr!
hPrint :: Show a => Handle -> a -> IO () Source
Вычисление hPrint hdl t записывает строковое представление t, заданное функцией show, в файл или канал, управляемый hdl, и добавляет символ перевода строки.
Данная операция может завершиться теми же ошибками, что и 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 () Source
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 :: Символ -> IO () Источник
Записать символ в стандартное устройство вывода
putChar реализовано как hPutChar stdout.
Эта операция может завершиться ошибкой по тем же причинам, что и hPutChar.
Примеры
Обратите внимание, что следующие действия не добавляют перевод строки.
>>> putChar 'x' x
>>> putChar '\0042' *
putStr :: Строка -> IO () Источник
Записать строку в стандартное устройство вывода
putStr реализовано как hPutStr stdout.
Эта операция может завершиться ошибкой по тем же причинам, и имеет те же проблемы с конкурентностью, что и hPutStr!
Примеры
Обратите внимание, что следующие действия не добавляют перевод строки.
>>> putStr "Hello, World!" Hello, World!
>>> putStr "\0052\0042\0050" 4*2
putStrLn :: Строка -> 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 Строка Источник
Операция 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 Строка Источник
Операция 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 => Строка -> 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 :: ПутьКФайлу -> РежимФайла -> (ДескрипторФайла -> IO r) -> IO r Источник
Вычисление withBinaryFile path mode action открывает бинарный файл и выполняет action с полученным дескриптором файла перед закрытием бинарного файла.
Это отличается от withFile, поскольку в нём не используется кодировка файла.
Даже если исключение возникает внутри action, файл всё равно будет закрыт. Именно поэтому withBinaryFile path mode act предпочтительнее
openBinaryFile path mode >>= (\hdl -> act hdl >>= hClose hdl)
См. также: bracket
Аргументы
| :: ПутьКФайлу | Путь к бинарному файлу, который должен быть открыт |
| -> РежимФайла | Режим, в котором должен быть открыт бинарный файл |
| -> IO ДескрипторФайла |
Вычисление openBinaryFile path mode возвращает дескриптор файла, который может быть использован для взаимодействия с бинарным файлом.
Это отличается от openFile, поскольку в нём не используется кодировка файла.
hSetBinaryMode :: ДескрипторФайла -> Булево -> IO () Источник
Выбор бинарного режима (True) или текстового режима (False) для открытого дескриптора файла. (См. также openBinaryFile.)
Это имеет тот же эффект, что и вызов hSetEncoding с char8, вместе с hSetNewlineMode с noNewlineTranslation.
hPutBuf :: Handle -> Ptr a -> Int -> IO () Source
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 Source
hGetBuf hdl buf count считывает данные из обработчика hdl в буфер buf до тех пор, пока не будет достигнут EOF или count 8-битных байтов не будут прочитаны. Возвращает количество фактически прочитанных байтов. Может быть нулем, если EOF был достигнут до чтения каких-либо данных (или если count равно нулю).
hGetBuf никогда не генерирует исключение EOF, вместо этого возвращает значение, меньшее, чем count.
Если обработчик является каналом или сокетом, а конечная точка записи закрыта, hGetBuf будет вести себя так, как будто достигнут EOF.
hGetBuf игнорирует текущую TextEncoding и NewlineMode на Handle, и считывает байты напрямую.
hGetBufSome :: Handle -> Ptr a -> Int -> IO Int Source
hGetBufSome hdl buf count считывает данные из обработчика hdl в буфер buf. Если доступны какие-либо данные для чтения, то hGetBufSome возвращает их немедленно; блокируется только если нет данных для чтения.
Возвращает количество фактически прочитанных байтов. Может быть нулем, если EOF был достигнут до чтения каких-либо данных (или если count равно нулю).
hGetBufSome никогда не генерирует исключение EOF, вместо этого возвращает значение, меньшее, чем count.
Если обработчик является каналом или сокетом, а конечная точка записи закрыта, hGetBufSome будет вести себя так, как будто достигнут EOF.
hGetBufSome игнорирует текущую TextEncoding и NewlineMode на Handle, и считывает байты напрямую.
hPutBufNonBlocking :: Handle -> Ptr a -> Int -> IO Int Source
hGetBufNonBlocking :: Handle -> Ptr a -> Int -> IO Int Source
hGetBufNonBlocking hdl buf count считывает данные из обработчика hdl в буфер buf до тех пор, пока не будет достигнут EOF или count 8-битных байтов не будут прочитаны, или пока не закончится доступная для немедленного чтения информация.
hGetBufNonBlocking идентично hGetBuf, за исключением того, что оно никогда не будет блокироваться в ожидании появления данных, вместо этого возвращает только доступные данные.
Чтобы дождаться появления данных перед вызовом hGetBufNonBlocking, используйте hWaitForInput.
Если обработчик является каналом или сокетом, а конечная точка записи закрыта, hGetBufNonBlocking будет вести себя так, как будто достигнут EOF.
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) Source
Как openTempFile, но открывает файл в двоичном режиме. См. openBinaryFile для дополнительных комментариев.
openTempFileWithDefaultPermissions :: FilePath -> String -> IO (FilePath, Handle) Source
Как openTempFile, но использует стандартные разрешения файла.
openBinaryTempFileWithDefaultPermissions :: FilePath -> String -> IO (FilePath, Handle) Source
Как openBinaryTempFile, но использует стандартные разрешения файла.
Кодирование/декодирование Unicode
В текстовом режиме Handle связан с TextEncoding, который используется для декодирования байтов в символы Unicode при чтении и кодирования символов Unicode в байты при записи.
По умолчанию TextEncoding такой же, как кодировка по умолчанию вашей системы, также доступная как localeEncoding. (Примечание GHC: в Windows мы в настоящее время не поддерживаем кодировки с двойным байтом; если кодовая страница консоли не поддерживается, тогда localeEncoding будет latin1.)
Ошибки кодирования и декодирования всегда обнаруживаются и сообщаются, за исключением ленивых ввода/вывода (hGetContents, getContents, и readFile), где ошибка декодирования просто приводит к прекращению потока символов, как и другие ошибки ввода/вывода.
hSetEncoding :: Handle -> TextEncoding -> IO () Source
Действие hSetEncoding hdl encoding изменяет кодировку текста для дескриптора hdl на encoding. По умолчанию, при создании Handle используется кодировка localeEncoding, а именно, кодировка по умолчанию для текущей локали.
Чтобы создать Handle без какой-либо кодировки, используйте openBinaryFile. Чтобы прекратить дальнейшее кодирование или декодирование существующего Handle, используйте hSetBinaryMode.
hSetEncoding может потребоваться очистить буферизованные данные для изменения кодировки.
hGetEncoding :: Handle -> IO (Maybe TextEncoding) Source
Возвращает текущую TextEncoding для указанного Handle, или Nothing если Handle находится в двоичном режиме.
Обратите внимание, что TextEncoding ничего не запоминает о состоянии используемого кодировщика/декодировщика в этом Handle. Например, если используемая кодировка — UTF-16, то использование hGetEncoding и hSetEncoding для сохранения и восстановления кодировки может привести к записи дополнительного байтового порядка в файл.
Кодировки Unicode
data TextEncoding Source
TextEncoding — это спецификация схемы преобразования между последовательностями байтов и последовательностями символов Юникода.
Например, UTF-8 — это кодировка символов Юникода в последовательность байтов. TextEncoding для UTF-8 — utf8.
Примеры
| Show TextEncoding Source | Начиная с: base-4.3.0.0 |
Определено в GHC.Internal.IO.Encoding.Types МетодыshowsPrec :: Int -> TextEncoding -> ShowS Source show :: TextEncoding -> String Source showList :: [TextEncoding] -> ShowS Source | |
Кодировка Latin1 (ISO8859-1). Эта кодировка напрямую отображает байты на первые 256 кодов Юникода и, следовательно, не является полной кодировкой Юникода. Попытка записать символ, больший чем '\255' в Handle с помощью кодировки latin1 приведет к ошибке.
Кодировка Unicode UTF-8.
utf8_bom :: TextEncoding Source
Кодировка Unicode UTF-8 с байтовой меткой порядка байтов (BOM; последовательность байтов 0xEF 0xBB 0xBF). Эта кодировка ведет себя как utf8, за исключением того, что при вводе последовательность BOM игнорируется в начале потока, а при выводе — добавляется в начало.
Метка порядка байтов в UTF-8 строго не нужна, но иногда используется для определения кодировки файла.
Кодировка Unicode UTF-16 (должна использоваться метка порядка байтов для указания порядка следования).
utf16le :: TextEncoding Source
Кодировка Unicode UTF-16 (малозначный порядок байтов).
utf16be :: TextEncoding Source
Кодировка Unicode UTF-16 (большой порядок байтов).
Кодировка Unicode UTF-32 (должна использоваться метка порядка байтов для указания порядка следования).
utf32le :: TextEncoding Source
Кодировка Unicode UTF-32 (малозначный порядок байтов).
utf32be :: TextEncoding Source
Кодировка Unicode UTF-32 (большой порядок байтов).
localeEncoding :: TextEncoding Source
Кодировка текущей локали.
Это начальная кодировка локали: если она была позже изменена с помощью setLocaleEncoding, это значение не отразит этого изменения.
Кодировка, в которой символы Юникода преобразуются в байты, беря остаток от деления кода символа на 256. При декодировании байты преобразуются непосредственно в эквивалентный код символа.
Эта кодировка никогда не терпит неудачу ни в одном направлении. Однако кодирование отбрасывает информацию, поэтому кодирование, за которым следует декодирование, не является тождественным отображением.
Начиная с: base-4.4.0.0
mkTextEncoding :: String -> IO TextEncoding Source
Поиск указанной кодировки Юникода. Может завершиться ошибкой
-
isDoesNotExistErrorесли кодировка неизвестна
Набор известных кодировок зависит от системы, но включает по крайней мере:
UTF-8
-
UTF-16,UTF-16BE,UTF-16LE -
UTF-32,UTF-32BE,UTF-32LE
Существует дополнительная нотация (заимствованная из GNU iconv) для указания обработки недопустимых символов:
- Суффикс
//IGNORE, например,UTF-8//IGNORE, приведет к тому, что все недопустимые последовательности на входе будут игнорироваться, а на выходе будут отброшены все символы, у которых нет представления в кодировке назначения. - Суффикс
//TRANSLITвыберет заменяющий символ для недопустимых последовательностей или символов. - Суффикс
//ROUNDTRIPиспользует механизм эскейпа в стиле PEP383 для представления любых недопустимых байтов на входе как кодов Юникода (в частности, как одиночных суррогатов, которые обычно недопустимы в 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' на выходе.
По умолчанию NewlineMode для Handle составляет nativeNewlineMode, что не выполняет перевод на Unix-системах, но переводит '\r\n' в '\n' и обратно в Windows.
В двоичном режиме Handle перевод новых строк вообще не выполняется.
hSetNewlineMode :: Handle -> NewlineMode -> IO () Source
Установите NewlineMode для указанного Handle. Все буферизованные данные сначала сбрасываются.
Представление новой строки во внешнем файле или потоке.
Примеры использования
nativeNewline :: Символ новой строки Исходный код
Представление символа новой строки для текущей платформы: 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.12.1/docs/libraries/base-4.21.0.0-8e62/System-IO.html