首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用haskell编写结构化二进制文件

用haskell编写结构化二进制文件
EN

Stack Overflow用户
提问于 2014-04-26 13:27:09
回答 2查看 763关注 0票数 2

我想用Haskell编写一个结构化的二进制文件。例如,假设前四个字节应该是"TEST“(作为ASCII),然后是数字1、2、3、4,然后是值128的32个字节,然后是以Little Endian格式表示的号码2048。

这意味着,创建的文件(作为十六进制)应该如下所示:

54 45 53 54 01 02 03 04 80 80 . 30字节

所以基本上我有一个自定义的数据结构,比如说

代码语言:javascript
复制
data MyData = MyData {
  header :: String     -- "TEST"
  n1     :: Integer    -- 1
  n2     :: Integer    -- 2
  n3     :: Integer    -- 3
  block  :: [Integer]  -- 32 times 128
  offset :: Integer    -- 2048
}

现在,我想将这些数据写入文件。基本上,我需要把这个结构转换成一个长的ByteString。我找不到一个干净的惯用的方法来做这件事。理想情况下,我有一个功能

代码语言:javascript
复制
MyDataToByteString :: MyData -> ByteString

代码语言:javascript
复制
MyDataToPut :: MyData -> Put

但我找不出如何创建这样一个函数。

背景信息:我想写一首歌曲的脉冲跟踪器格式(http://schismtracker.org/wiki/ITTECH.TXT),这是二进制格式的分裂跟踪软件。

更新1

对于endian转换,我想我可以提取单个Bytes,如下所示:

代码语言:javascript
复制
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]
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-04-26 14:06:39

你可以试试这个(恐怕不是最优的):

代码语言:javascript
复制
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)
    ]
票数 2
EN

Stack Overflow用户

发布于 2014-04-26 17:37:17

binarycereal包提供了简单的ByteString数据结构序列化。下面是一个使用binary的示例

代码语言:javascript
复制
{-# 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进行反序列化。

代码语言:javascript
复制
λ. 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}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23311559

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档