假设我有以下类型:
data WaveFormatChunk = WaveFormatChunk {
compression :: Word16,
channels :: Word16,
sampleRate :: Word32,
averageBps :: Word32,
blockAlign :: Word16,
significantBits :: Word16
} deriving (Show)
有没有办法将所有这些转换为ByteString(或类似结构)批发(以你的C形式的方式)?如果没有,我必须编写一个单独将它们全部放入列表的函数,是否至少有将函数粘贴到Word8列表中的函数?像putWordBBxe这样的东西,除了字节字符串或列表(虽然我很可能因为我还没有正确读入Monads而严重错误,但在我看来,Get / Put主要用于流)。
Data.Binary不是我正在寻找的东西,对于仅仅在磁盘上转储数据而不是以具有特定(和“错误”)字节顺序的特定格式存储数据似乎更有用。
答案 0 :(得分:12)
Data.Binary将允许您使用显式little-endian operators将结构序列化为字节字符串。
{-# OPTIONS_GHC -funbox-strict-fields #-}
{-# LANGUAGE RecordWildCards #-}
import Data.Binary
import Data.Binary.Put
import qualified Data.ByteString.Char8 as C
import qualified Data.ByteString.Lazy as L
data WaveFormatChunk =
WaveFormatChunk {
compression :: !Word16,
channels :: !Word16,
sampleRate :: !Word32,
averageBps :: !Word32,
blockAlign :: !Word16,
significantBits :: !Word16
}
instance Binary WaveFormatChunk where
put (WaveFormatChunk{..}) = do
putWord16le compression
putWord16le channels
putWord32le sampleRate
putWord32le averageBps
putWord16le blockAlign
putWord16le significantBits
get = undefined
main = C.putStr $ C.concat $ L.toChunks $ encode test
where
test = WaveFormatChunk {
compression = 0xcafe
, channels = 0xface
, sampleRate = 0xdeadbeef
, averageBps = 0xf01dab1e
, blockAlign = 0x5566
, significantBits = 0xb01d
}
将屈服:
$ ./A | od -x
0000000 cafe face beef dead ab1e f01d 5566 b01d
因此,您可以对表示进行精确的字节级控制。如果您对流式传输不感兴趣,也可以从谷物包装中获得相同的效果。
答案 1 :(得分:4)
还有另一种完全不同的方法。您可以定义ByteString
包装器
import Data.ByteString (ByteString)
newtype WaveFormatChunk =
WaveFormatChunk {
getWaveFormatChunk :: ByteString
}
将此文件写入文件非常简单。要修改这种结构,您可以使用镜头:
data Compression = {- ... -}
compression :: Lens' WaveFormatChunk Compression
或者如果您愿意:
compression :: Lens' WaveFormatChunk Word16
镜头就像个别字节组的安全解释器一样。但是,有三个问题:首先你应该为那个使用测试框架,因为很容易让镜头出错。其次,每次更改都需要ByteString的新副本。根据您的操作,这可能比原始方法更慢或更快。
我个人建议使用常规的高级Haskell数据类型并使用正确的序列化。正如其他人所指出的,这些实例很容易编写。