5

我需要在 Haskell 中读取二进制格式。格式相当简单:四个八位字节表示数据的长度,然后是数据。四个八位字节表示网络字节顺序中的整数。

如何将ByteString四个字节的 a 转换为整数?我想要一个直接转换(在 C 中,那将是*(int*)&data),而不是字典转换。另外,我将如何处理字节顺序?序列化的整数按网络字节顺序排列,但机器可能使用不同的字节顺序。

我尝试了谷歌搜索,但只有关于字典转换的结果。

4

3 回答 3

12

二进制包包含从 ByteStrings 获取各种大小和字节序的整数类型的工具。

λ> :set -XOverloadedStrings
λ> import qualified Data.Binary.Get as B
λ> B.runGet B.getWord32be "\STX\SOH\SOH\SOH"
33620225
λ> B.runGet B.getWord32be "\STX\SOH\SOH\SOHtrailing characters are ignored"
33620225
λ> B.runGet B.getWord32be "\STX\SOH\SOH" -- remember to use `catch`:
*** Exception: Data.Binary.Get.runGet at position 0: not enough bytes
CallStack (from HasCallStack):
  error, called at libraries/binary/src/Data/Binary/Get.hs:351:5 in binary-0.8.5.1:Data.Binary.Get
于 2013-01-15T10:37:34.500 回答
5

我假设您可以使用折叠,然后使用其中一个foldlfoldr来确定您想要哪个字节序(我忘记了哪个字节序)。

foldl :: (a -> Word8 -> a) -> a -> ByteString -> a

我认为这将适用于二元运算符:

foo :: Int -> Word8 -> Int
foo prev v = (prev * 256) + v
于 2013-01-15T10:35:54.673 回答
4

我只需提取前四个字节并使用Data.Bits中的函数将它们合并为一个 32 位整数:

import qualified Data.ByteString.Char8 as B
import Data.Char (chr, ord)
import Data.Bits (shift, (.|.))
import Data.Int (Int32)

readInt :: B.ByteString -> Int32
readInt bs = (byte 0 `shift` 24)
             .|. (byte 1 `shift` 16)
             .|. (byte 2 `shift` 8)
             .|. byte 3
        where byte n = fromIntegral $ ord (bs `B.index` n)

sample = B.pack $ map chr [0x01, 0x02, 0x03, 0x04]
main = print $ readInt sample -- prints 16909060
于 2013-01-15T10:42:16.700 回答