我想用Haskell编写一个结构化的二进制文件。例如,假设前四个字节应该是"TEST“(作为ASCII),然后是数字1、2、3、4,然后是值128的32个字节,然后是以Little Endian格式表示的号码2048。
这意味着,创建的文件(作为十六进制)应该如下所示:
54 45 53 54 01 02 03 04 80 80 . 30字节
所以基本上我有一个自定义的数据结构,比如说
data MyData = MyData {
header :: String -- "TEST"
n1 :: Integer -- 1
n2 :: Integer -- 2
n3 :: Integer -- 3
block :: [Integer] -- 32 times 128
offset :: Integer -- 2048
}现在,我想将这些数据写入文件。基本上,我需要把这个结构转换成一个长的ByteString。我找不到一个干净的惯用的方法来做这件事。理想情况下,我有一个功能
MyDataToByteString :: MyData -> ByteString或
MyDataToPut :: MyData -> Put但我找不出如何创建这样一个函数。
背景信息:我想写一首歌曲的脉冲跟踪器格式(http://schismtracker.org/wiki/ITTECH.TXT),这是二进制格式的分裂跟踪软件。
更新1
对于endian转换,我想我可以提取单个Bytes,如下所示:
getByte :: Int -> Int -> Int
getByte b num = shift (num .&. bitMask b) (8-8*b)
where bitMask b = sum $ map (2^) [8*b-8 .. 8*b-1]发布于 2014-04-26 14:06:39
你可以试试这个(恐怕不是最优的):
import qualified Data.List as L
import qualified Data.ByteString.Char8 as BC
import qualified Data.ByteString as B
data MyData = MyData {
header :: String -- "TEST"
, n1 :: Integer -- 1
, n2 :: Integer -- 2
, n3 :: Integer -- 3
, n4 :: Integer -- 4
, block :: [Integer] -- 32 times 128
, offset :: [Integer] -- 2048 in little endian
} deriving (Show)
d = MyData "TEST" 1 2 3 4 (L.replicate 32 128) [0, 8]
myDataToByteString :: MyData -> B.ByteString
myDataToByteString (MyData h n1 n2 n3 n4 b o) =
B.concat [
BC.pack h
, B.pack (map fromIntegral [n1, n2, n3, n4])
, B.pack (map fromIntegral b)
, B.pack (map fromIntegral o)
]发布于 2014-04-26 17:37:17
binary或cereal包提供了简单的ByteString数据结构序列化。下面是一个使用binary的示例
{-# LANGUAGE DeriveGeneric #-}
import Data.Binary
import qualified Data.ByteString.Char8 as B8
import Data.Word8
import GHC.Generics
data MyData = MyData
{ header :: B8.ByteString
, n1 :: Int
, n2 :: Int
, n3 :: Int
, n4 :: Int
, block :: [Word8]
, offset :: Int
} deriving (Generic, Show)
instance Binary MyData
myData = MyData (B8.pack "Test") 1 2 3 4 (replicate 32 128) 2048注意,我已经将block的类型更改为[Word8],因为问题说明这些都是字节。
我们为MyData派生了一个MyData实例,该实例允许binary包自动生成Binary实例。现在,我们可以使用ByteString将数据序列化为encode,并使用decode进行反序列化。
λ. let encoded = encode myData
λ. :t encoded
encoded :: Data.ByteString.Lazy.Internal.ByteString
λ. let decoded = decode encoded :: MyData
λ. decoded
MyData {header = "Test", n1 = 1, n2 = 2, n3 = 3, n4 = 4, block = [128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128], offset = 2048}https://stackoverflow.com/questions/23311559
复制相似问题