Data.Binary.Получить
| Авторские права | Леннарт Колмодин |
|---|---|
| Лицензия | BSD3-стиль (см. LICENSE) |
| Поддерживающий | Леннарт Колмодин <kolmodin@gmail.com> |
| Устойчивость | экспериментальная |
| Портируемость | портативная для Hugs и GHC. |
| Безопасный Haskell | Надежный |
| Язык | Haskell98 |
Содержание
Описание
Моноид Get. Моноид для эффективного построения структур из закодированных ленивых массивов байтов.
Доступны примитивы для декодирования слов различных размеров, как Big-endian, так и Little-endian.
Давайте декодируем двоичные данные, представленные здесь. В этом примере значения находятся в формате Little-endian.
+------------------+--------------+-----------------+ | 32 bit timestamp | 32 bit price | 16 bit quantity | +------------------+--------------+-----------------+
Соответствующее значение Haskell выглядит так:
data Trade = Trade
{ timestamp :: !Word32
, price :: !Word32
, qty :: !Word16
} deriving (Show)
Поля в Trade помечены как жёсткие (используя !) так как нам здесь не нужна ленивость. На практике, вы, вероятно, также рассмотрите использование директивы UNPACK.
Теперь давайте посмотрим на декодер для этого формата.
getTrade ::GetTrade getTrade = do timestamp <-getWord32leprice <-getWord32lequantity <-getWord16lereturn$!Trade timestamp price quantity
Или даже проще, используя стилевую прикладную функцию:
getTrade' ::GetTrade getTrade' = Trade<$>getWord32le<*>getWord32le<*>getWord16le
Стиль с применением функций иногда приводит к более быстрому коду, так как binary попытается оптимизировать код, объединив чтения вместе.
Существует два типа способов выполнения этого декодера: ленивый и инкрементальный методы ввода. Здесь мы будем использовать ленивый метод.
Сначала определим функцию, которая декодирует много Trade.
getTrades :: Get [Trade]
getTrades = do
empty <- isEmpty
if empty
then return []
else do trade <- getTrade
trades <- getTrades
return (trade:trades)
Наконец, запустим декодер:
lazyIOExample :: IO [Trade]
lazyIOExample = do
input <- BL.readFile "trades.bin"
return (runGet getTrades input)
Этот декодер имеет недостаток, что ему нужно прочитать весь ввод, прежде чем он сможет вернуть результат. С другой стороны, он ничего не вернёт, пока не узнает, что может декодировать всё без ошибок.
Вы также можете переписать на лево-fold, чтобы декодировать в более потоковом режиме и получить следующий декодер. Он начнет возвращать данные, не зная, что может декодировать весь ввод.
incrementalExample :: BL.ByteString -> [Trade]
incrementalExample input0 = go decoder input0
where
decoder = runGetIncremental getTrade
go :: Decoder Trade -> BL.ByteString -> [Trade]
go (Done leftover _consumed trade) input =
trade : go decoder (BL.chunk leftover input)
go (Partial k) input =
go (k . takeHeadChunk $ input) (dropHeadChunk input)
go (Fail _leftover _consumed msg) _input =
error msg
takeHeadChunk :: BL.ByteString -> Maybe BS.ByteString
takeHeadChunk lbs =
case lbs of
(BL.Chunk bs _) -> Just bs
_ -> Nothing
dropHeadChunk :: BL.ByteString -> BL.ByteString
dropHeadChunk lbs =
case lbs of
(BL.Chunk _ lbs') -> lbs'
_ -> BL.Empty
lazyIOExample использует ленивые вводы для чтения файла с диска, что не подходит для всех применений, и определенно не подходит, если вам нужно читать из сокета, в котором выше вероятность ошибки. Чтобы решить эти задачи, используйте инкрементальный интерфейс ввода, как в incrementalExample. Пример того, как читать инкрементально из Handle, см. в реализации decodeFileOrFail в Data.Binary.
Моноид Get
Ленивый интерфейс ввода
Ленивый интерфейс потребляет один ленивый ByteString. Это самый простой интерфейс для начала работы, но он не поддерживает вложение ввода-вывода и разбора, если не используется ленивое ввод-вывод.
Нет способа предоставить больше ввода, кроме начальных данных. Чтобы иметь возможность по частям предоставлять данные, см. инкрементальный интерфейс ввода.
runGet :: Get a -> ByteString -> a Источник
Самый простой интерфейс для запуска декодера Get. Если декодер столкнётся с ошибкой, вызовет fail, или закончится вводом, он вызовет error.
runGetOrFail :: Get a -> ByteString -> Either (ByteString, СмещениеБайта, Строка) (ByteString, СмещениеБайта, a) Источник
Запуск моноида Get и возврат Left при ошибке и Right при успехе. В обоих случаях возвращается неиспользованный ввод и количество израсходованных байтов. В случае ошибки также включается удобочитаемое сообщение об ошибке.
type СмещениеБайта = Int64 Источник
Смещение, отсчитываемое в байтах.
Инкрементальный интерфейс ввода
Инкрементальный интерфейс даёт вам больший контроль над тем, как предоставляется ввод во время разбора. Это позволяет, например, вкладывать ввод-вывод и разбор.
Инкрементальный интерфейс потребляет жёсткий ByteString за раз, каждый из которых является частью общего количества ввода. Если вашему декодеру нужен дополнительный ввод для завершения, он вернёт Partial с продолжением. Если больше нет ввода, предоставьте Nothing.
Fail вернётся, если произойдет ошибка, вместе с сообщением, позицией и оставшимся вводом. Если всё успешно, будет возвращено Done с результирующим значением, позицией и оставшимся вводом.
Декодер, полученный при запуске моноида Get. См. Decoder для дальнейших действий, таких как предоставление ввода, обработка ошибок декодера и получение выходного значения. Подсказка: Используйте вспомогательные функции pushChunk, pushChunks и pushEndOfInput.
Конструкторы
| Ошибка !ByteString !СмещениеБайта Строка | Декодер столкнулся с ошибкой. Декодер либо использовал |
| Частичный (Возможно ByteString -> Декодер a) | Декодер израсходовал имеющийся ввод и нуждается в большем для продолжения. Предоставьте |
| Закончен !ByteString !СмещениеБайта a | Декодер успешно завершен. Кроме выходного значения, вы также получаете любой неиспользованный ввод, а также количество израсходованных байтов. |
runGetIncremental :: Get a -> Декодер a Источник
Запуск моноида Get. См. Decoder для следующих шагов, таких как предоставление ввода, обработка ошибок декодера и получение выходного значения. Подсказка: Используйте вспомогательные функции pushChunk, pushChunks и pushEndOfInput.
Предоставление ввода
pushChunk :: Декодер a -> ByteString -> Декодер a Источник
Предоставление декодеру Decoder большего ввода. Если Decoder — Done или Fail, он добавит ввод к ByteString неиспользованного ввода.
runGetIncremental myParser `pushChunk` myInput1 `pushChunk` myInput2
pushChunks :: Декодер a -> ByteString -> Декодер a Источник
Предоставление декодеру Decoder большего ввода. Если Decoder — Done или Fail, он добавит ввод к ByteString неиспользованного ввода.
runGetIncremental myParser `pushChunks` myLazyByteString
pushEndOfInput :: Декодер a -> Декодер a Источник
Сообщите Decoder, что больше нет входных данных. Это передаёт Nothing декодеру Partial, в противном случае возвращает декодер без изменений.
Декодирование
skip :: Int -> Get () Исходный код
Пропустить вперёд n байтов. Возникает ошибка, если доступно меньше n байтов.
isEmpty :: Get Bool Исходный код
Проверить, были ли потреблены все входные данные, т.е. не осталось нераскодированных байтов.
bytesRead :: Get Int64 Исходный код
Получить общее количество считанных байтов на данный момент.
Аргументы
| :: Int | Количество байтов, которые необходимо потребить |
| -> Get a | Декодер, который необходимо изолировать |
| -> Get a |
Изолировать декодер для работы с фиксированным количеством байтов и возвращать ошибку, если потреблялось меньше или пытались потребить больше байтов. Если указанный декодер возвращает ошибку, то и функция isolate также вернёт ошибку. Смещение от bytesRead будет относиться к началу isolate, а не к абсолютному началу входных данных.
lookAhead :: Get a -> Get a Исходный код
Запустить указанный декодер, но не потреблять его входные данные. Если указанный декодер возвращает ошибку, то и эта функция тоже вернёт ошибку.
lookAheadM :: Get (Maybe a) -> Get (Maybe a) Исходный код
Запустить заданный декодер и потребить его входные данные только если он вернёт Just. Если вернётся Nothing, входные данные останутся непотребленными. Если заданный декодер возвращает ошибку, то и эта функция тоже вернёт ошибку.
lookAheadE :: Get (Either a b) -> Get (Either a b) Исходный код
Запустить заданный декодер и потреблять его входные данные только если он вернёт Right. Если вернётся Left, входные данные останутся непотребленными. Если заданный декодер возвращает ошибку, то и эта функция тоже вернёт ошибку.
label :: String -> Get a -> Get a Исходный код
Массивы байтов
getByteString :: Int -> Get ByteString Исходный код
Эффективный метод get для строгих массивов байтов. Возникает ошибка, если осталось меньше n байтов во входных данных. Если n <= 0, то возвращается пустая строка.
getLazyByteString :: Int64 -> Get ByteString Исходный код
Эффективный метод get для ленивых массивов байтов. Возникает ошибка, если осталось меньше n байтов во входных данных.
getLazyByteStringNul :: Get ByteString Исходный код
Получить ленивый массив байтов, завершаемый байтом NULL. Возвращаемая строка не содержит байт NULL. Возникает ошибка, если достигнут конец входных данных, не найдя байт NULL.
getRemainingLazyByteString :: Get ByteString Исходный код
Получить оставшиеся байты в виде ленивого массива байтов. Обратите внимание, что это может быть дорогостоящая функция, так как она заставляет читать все входные данные и сохранять строку в памяти.
Декодирование слов
getWord8 :: Get Word8 Исходный код
Считать Word8 из состояния монады.
Декодирование в формате big-endian
getWord16be :: Get Word16 Исходный код
Считать Word16 в формате big-endian.
getWord32be :: Get Word32 Исходный код
Считать Word32 в формате big-endian.
getWord64be :: Get Word64 Исходный код
Считать Word64 в формате big-endian.
Декодирование в формате little-endian
getWord16le :: Get Word16 Исходный код
Считать Word16 в формате little-endian.
getWord32le :: Get Word32 Исходный код
Считать Word32 в формате little-endian.
getWord64le :: Get Word64 Исходный код
Считать Word64 в формате little-endian.
Декодирование в формате host-endian, без выравнивания
getWordhost :: Get Word Исходный код
O(1). Считать одно слово, используемое на текущей машине. Слово читается в порядке, принятом для текущей машины, в формате host-endian. На 64-битной машине Word — значение в 8 байтов, на 32-битной машине — 4 байта.
getWord16host :: Get Word16 Исходный код
O(1). Считать 2-байтовое Word16 в порядке host-order и формате host-endian.
getWord32host :: Get Word32 Исходный код
O(1). Считать Word32 в порядке host-order и формате host-endian.
getWord64host :: Get Word64 Исходный код
O(1). Считать Word64 в порядке host-order и формате host-endian.
Функции, устаревшие
runGetState :: Get a -> ByteString -> ByteOffset -> (a, ByteString, ByteOffset) Исходный код
Устаревшее: Используйте runGetIncremental вместо этого. Эта функция будет удалена.
УСТАРЕВШЕЕ. Обеспечивает совместимость с предыдущими версиями этой библиотеки. Выполняет Get монаду и возвращает кортеж с тремя значениями. Первое значение — результат декодера. Второе и третье — неиспользованный ввод и количество прочитанных байтов.
remaining :: Get Int64 Источник
Устаревшее: Это принудительно прочитает весь оставшийся ввод, не используйте это.
УСТАРЕВШЕЕ. Получает количество байтов оставшегося ввода. Обратите внимание, что эта функция является дорогостоящей, поскольку для расчета оставшегося ввода необходимо прочитать весь ввод и сохранить его в памяти. Декодер сохраняет ввод как строгую строку байтов, поэтому вам, вероятно, лучше рассчитать оставшийся ввод другим способом.
getBytes :: Int -> Get ByteString Источник
Устаревшее: Используйте getByteString вместо getBytes.
УСТАРЕВШЕЕ. То же, что и getByteString.
© The University of Glasgow and others
Licensed under a BSD-style license (see top of the page).
https://downloads.haskell.org/~ghc/7.10.3/docs/html/libraries/binary-0.7.5.0/Data-Binary-Get.html