Spec-Zone.ru › Haskell 7

Data.Binary.Получить

Авторские права Леннарт Колмодин
Лицензия BSD3-стиль (см. LICENSE)
Поддерживающий Леннарт Колмодин <kolmodin@gmail.com>
Устойчивость экспериментальная
Портируемость портативная для Hugs и GHC.
Безопасный Haskell Надежный
Язык Haskell98

Содержание

  • Моноид Get
  • Ленивый интерфейс ввода
  • Инкрементальный интерфейс ввода
    • Предоставление ввода
  • Декодирование
    • Массивы байтов
    • Декодирование слов
      • Декодирование с порядком байт Big-endian
      • Декодирование с порядком байт Little-endian
      • Декодирование с порядком байт Host-endian, невыровненное
  • Устаревшие функции

Описание

Моноид 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.

http://www.haskell.org/ghc/docs/latest/html/users_guide/pragmas.html#unpack-pragma

Теперь давайте посмотрим на декодер для этого формата.

getTrade :: Get Trade
getTrade = do
  timestamp <- getWord32le
  price     <- getWord32le
  quantity  <- getWord16le
  return $! Trade timestamp price quantity
 

Или даже проще, используя стилевую прикладную функцию:

getTrade' :: Get Trade
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

data Get a Источник

Примеры

Моноид Get
Функтор Get
Прикладная функция Get
Альтернатива Get
Моноид с объединением 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 с результирующим значением, позицией и оставшимся вводом.

data Декодер a Источник

Декодер, полученный при запуске моноида Get. См. Decoder для дальнейших действий, таких как предоставление ввода, обработка ошибок декодера и получение выходного значения. Подсказка: Используйте вспомогательные функции pushChunk, pushChunks и pushEndOfInput.

Конструкторы

Ошибка !ByteString !СмещениеБайта Строка

Декодер столкнулся с ошибкой. Декодер либо использовал fail либо не получил достаточный ввод. Содержит любой неиспользованный ввод и количество израсходованных байтов.

Частичный (Возможно ByteString -> Декодер a)

Декодер израсходовал имеющийся ввод и нуждается в большем для продолжения. Предоставьте Just если доступен дополнительный ввод и Nothing в противном случае, и вы получите новый Decoder.

Закончен !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 Исходный код

Получить общее количество считанных байтов на данный момент.

isolate Исходный код

Аргументы

:: 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API