处理哈斯克尔zlib的解压错误(Handling Haskell zlib decompressio

2019-10-19 08:40发布

我有一个字符串x可能会或可能不会是gzip压缩。 使用zlib图书馆,我想尝试解压x -如果成功,该函数将返回压缩字符串。 如果不是(即x不是用gzip压缩的),我想简单的返回x

作为GZip.decompress产生一个error ,如果适用于非gzip的字符串,我可以用catch或相似,但我专门要求使用该解决方案zlib错误处理机制。

我怎么可以编写一个函数,说decompressIfPossible :: ByteString -> ByteString已经先前描述的特征? 我宁愿一个Either String ByteString来表示任何错误或减压的结果。

注意:这个问题故意不显示的研究工作,因为它是在一个Q&A式地立即回答。

Answer 1:

从功能zlib你需要在这里使用被称为decompressWithErrors 。 它的值是递归DecompressStream数据结构,可以折叠成一个ByteStringv:fromDecompressStream

这里有一个如何写你要的功能,一个完整的例子:

import Data.Either
import Codec.Compression.Zlib.Internal
import qualified Data.ByteString.Lazy.Char8 as LB

-- | Convert & unfold the custom DecompressStream
--   error format from zlib to a Either
decompressStreamToEither :: DecompressStream -> Either String LB.ByteString
decompressStreamToEither (StreamError _ errmsg) = Left errmsg
decompressStreamToEither stream@(StreamChunk _ _) = Right $ fromDecompressStream stream
decompressStreamToEither StreamEnd = Right $ ""

-- | Decompress with explicit error handling
safeDecompress :: LB.ByteString -> Either String LB.ByteString
safeDecompress bstr = decompressStreamToEither $ decompressWithErrors gzipOrZlibFormat defaultDecompressParams bstr

-- | Decompress gzip, if it fails, return uncompressed String
decompressIfPossible :: LB.ByteString -> LB.ByteString
decompressIfPossible bstr =
    let conv (Left a) = bstr
        conv (Right a) = a
    in (conv . safeDecompress) bstr

注意,这个例子使用gzipOrZlibFormat如果标题是一个ZLIB或gzip头,其自动检测。



文章来源: Handling Haskell zlib decompression errors