Loops 在IO中编写循环的更好方法
给定一个png文件,我试图得到它的块偏移量和大小的列表 简言之,由块组成,每个块由三个4字节字段加上一个可变长度字段(块的数据字段)组成。数据字段的大小存储在第一个4字节字段(称为“长度”字段)中 因此,给定当前块的偏移量和大小(ofs,sz),我们可以通过这种方式导出下一个块的偏移量和大小(ofs',sz'): ofs'=ofs+sz 读取sz'偏移量=ofs' 给定初始块的偏移量和大小,在png文件中始终为(0,8),可以在文件中循环,直到到达其末端。我就是这样做的:Loops 在IO中编写循环的更好方法,loops,haskell,Loops,Haskell,给定一个png文件,我试图得到它的块偏移量和大小的列表 简言之,由块组成,每个块由三个4字节字段加上一个可变长度字段(块的数据字段)组成。数据字段的大小存储在第一个4字节字段(称为“长度”字段)中 因此,给定当前块的偏移量和大小(ofs,sz),我们可以通过这种方式导出下一个块的偏移量和大小(ofs',sz'): ofs'=ofs+sz 读取sz'偏移量=ofs' 给定初始块的偏移量和大小,在png文件中始终为(0,8),可以在文件中循环,直到到达其末端。我就是这样做的: import Data
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
导入数据.Word
将限定数据.ByteString.Lazy导入为BS
导入Data.Binary.Get
大小::BS.ByteString->Int->IO(Int)
大小字节偏移量=do
设ln=横档(不跳过偏移
l BS.ByteString->[(Int,Int)]->IO[(Int,Int)]
偏移量大小fLen字节oss=do
let(偏移量,sz)=最后一个oss
偏移量'=偏移量+sz
sz'offsetSizes
被反复输入某个状态(该(offset,sz)
对)以生成新的对或完成。创建的所有对都被收集到一个列表中
此递归方案由包中的捕获,允许您将offsetsize
作为
offsetSizes :: Int -> BS.ByteString -> IO [(Int, Int)]
offsetSizes fLen bytes = unfoldrM step (0, 8)
where
step (offset, sz) = do
let offset' = offset + sz
sz' <- size bytes offset'
let state' = (offset', sz')
return $ if offset' + sz' < fLen then Just (state', state') else Nothing
offsetsize::Int->BS.ByteString->IO[(Int,Int)]
offsetSizes fLen bytes=展开步骤(0,8)
哪里
步进(偏移量,sz)=do
设偏移量'=offset+sz
sz'我会使用类似于inoffsetSizes
;此外,您可以编写let ln=runGet(skip offset>>getWord32be)字节
来简化它。循环并没有那么糟糕。看起来糟糕的是重复的oss++[(offset',sz')]
,这是低效的。最好使用(offset',sz')):oss
创建一个反向列表,然后在循环结束后最终将其反向。这还可以避免最后一个oss
,这很慢。谢谢你的建议,我会尝试的。