【发布时间】:2015-08-31 19:00:39
【问题描述】:
给定一个 png 文件,我正在尝试获取其块的偏移量和大小的列表。
简而言之,png files 由块组成,每个块由三个 4 字节字段加上一个可变长度字段(块的数据字段)组成。数据字段的大小存储在第一个 4 字节字段中(称为“长度”字段)。
因此,给定当前块的偏移量和大小,(ofs, sz),就可以得出下一个块的偏移量和大小,(ofs', sz'):
ofs' = ofs + sz
在偏移量 = ofs' 处读取 sz'
给定初始块的偏移量和大小,在 png 文件中总是 (0, 8),可以循环遍历文件直到到达其末尾。我就是这样做的:
import Data.Word
import qualified Data.ByteString.Lazy as BS
import Data.Binary.Get
size :: BS.ByteString -> Int -> IO (Int)
size bytes offset = do
let ln = runGet (do skip offset
l <- getWord32be
return l)
bytes
return $ 3*4 + fromIntegral ln
offsetSizes :: Int -> BS.ByteString -> [(Int, Int)] -> IO [(Int, Int)]
offsetSizes fLen bytes oss = do
let (offset, sz) = last oss
offset' = offset + sz
sz' <- size bytes offset'
let nextOffset = offset' + sz'
if nextOffset < fLen then offsetSizes fLen bytes $ oss ++ [(offset', sz')]
else return oss
main = do
contents <- BS.readFile "myfile.png"
let fLen = fromIntegral $ BS.length contents :: Int
ofszs <- offsetSizes fLen contents [(0,8)]
putStrLn $ "# of chunks: " ++ (show $ length ofszs)
putStrLn $ "chunks [(offset,size)]: " ++ show ofszs
我的问题:我对循环不太满意。我想知道在 Haskell 中是否有更惯用的方法来实现相同的目标?
【问题讨论】:
-
我会在
offsetSizes中使用unfoldrM 之类的东西;另外,您可以写let ln = runGet (skip offset >> getWord32be) bytes使其更简单。 -
循环还不错。相反,看起来很糟糕的是重复的
oss ++ [(offset', sz')],这是低效的。最好使用(offset', sz') : oss构建一个反向列表,然后在循环结束后最终将其反向。这也可以让你避免last oss,这很慢。 -
谢谢你的建议,我试试看。