2013-02-17 5 views
5

Hãy nói rằng tôi có các loại sau đây:Làm thế nào để tuần tự hóa các POD không đáng kể?

data WaveFormatChunk = WaveFormatChunk { 
    compression :: Word16, 
    channels :: Word16, 
    sampleRate :: Word32, 
    averageBps :: Word32, 
    blockAlign :: Word16, 
    significantBits :: Word16 
    } deriving (Show) 

Có cách nào để chỉ cần đổ tất cả điều đó vào một ByteString (hoặc một cấu trúc tương tự) bán buôn (một cách của cấu trúc Ye Olde C)? Nếu không và tôi phải viết một hàm riêng biệt đặt tất cả chúng vào danh sách, có ít nhất các hàm để gắn giá trị vào một danh sách Word8 dễ không? Một cái gì đó giống như putWordBBxe, ngoại trừ chuỗi byte hoặc danh sách (mặc dù tôi rất có thể bị nhầm lẫn vì tôi chưa đọc chính xác vào Monads, dường như với tôi Get/Put hầu hết được sử dụng với các luồng).

Data.Binary không hoàn toàn là những gì tôi đang tìm kiếm, có vẻ hữu ích hơn khi chỉ đổ dữ liệu trên đĩa so với lưu trữ nó ở định dạng cụ thể với độ dài cụ thể (và "sai").

+1

Viết một phiên bản ['Storable'] (http://hackage.haskell.org/packages/archive/base/latest/doc/html/Foreign-Storable.html) cho' WaveFormatChunk' khá đơn giản. Điều đó sẽ cho phép bạn viết ('poke') và đọc (' peek') 'WaveFormatChunk' đến và từ các vị trí bộ nhớ (như thể chúng là các cấu trúc cũ của C). Sau đó, chúng có thể được chuyển thành 'ByteString's nếu bạn muốn. Tôi không biết đây có phải là điều bạn đang tìm kiếm hay không, nhưng tôi có thể giải thích nếu bạn muốn. Ngoài ra còn có [gói nhị phân] (http://hackage.haskell.org/package/binary) để tuần tự hóa. – gspr

+0

... oh, tôi thấy bản chỉnh sửa của tôi về gói nhị phân khá là vô giá trị vì bạn đã biết về điều đó :-) – gspr

+1

Đáng yêu chắc chắn là con đường để đi. Bạn sẽ không tiến gần hơn đến C hơn thế, cả về phong cách và hiệu quả thực hiện. [Đây là một ví dụ] (http://hpaste.org/76299). –

Trả lời

12

Data.Binary sẽ cho phép bạn tuần tự hóa cấu trúc để xác định quyền sở hữu, sử dụng rõ ràng 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 
          } 

sẽ mang lại:

$ ./A | od -x 
0000000 cafe face beef dead ab1e f01d 5566 b01d 

Vì vậy, bạn có quyền kiểm soát byte cấp chính xác của các đại diện. Bạn cũng có thể nhận được hiệu ứng tương tự từ gói ngũ cốc, nếu bạn không muốn phát trực tuyến.

+0

Cảm ơn - có thể là một câu hỏi vô lý, nhưng tôi chỉ mơ hồ quen thuộc với những tuyên bố nghiêm ngặt và tất cả nhạc jazz đi cùng họ ... là những tiếng nổ thực sự cần thiết? – jaymmer

+6

Chúng là vệ sinh tốt - bạn không cần sự lười biếng ở đây, sự lười biếng trên các loại nguyên tử hầu như luôn luôn sai - vì vậy hãy xác định rằng nó phải nghiêm ngặt. –

+1

Lưu ý rằng gói nhị phân giờ đây cũng hỗ trợ truyền trực tuyến, bạn không cần phải chọn giữa nhị phân và ngũ cốc nữa. –

4

Có một cách tiếp cận hoàn toàn khác. Thay vì có một cấu trúc như vậy bạn có thể xác định một wrapper ByteString:

import Data.ByteString (ByteString) 

newtype WaveFormatChunk = 
    WaveFormatChunk { 
     getWaveFormatChunk :: ByteString 
    } 

Viết này vào một tập tin được dễ dàng. Để sửa đổi một cấu trúc như vậy bạn có thể sử dụng ống kính:

data Compression = {- ... -} 

compression :: Lens' WaveFormatChunk Compression 

hoặc nếu bạn thích:

compression :: Lens' WaveFormatChunk Word16 

Các ống kính đóng vai trò như thông dịch an toàn của các nhóm byte cá nhân. Tuy nhiên, có ba vấn đề: Trước hết bạn nên sử dụng một khung kiểm tra cho khung đó, bởi vì dễ dàng để có được các ống kính sai. Thứ hai, mọi thay đổi đòi hỏi một bản sao mới của ByteString. Tùy thuộc vào những gì bạn làm điều này có thể chậm hơn hoặc nhanh hơn so với cách tiếp cận ban đầu của bạn.

Đề xuất cá nhân của tôi là đi với kiểu dữ liệu Haskell cao cấp thông thường và sử dụng tuần tự thích hợp. Như được chỉ ra bởi những người khác các trường hợp khá dễ dàng để viết.