处理Haskell zlib解压缩错误

时间:2014-02-14 04:03:54

标签: haskell gzip haskell-zlib

我有一个字符串x,它可能是也可能不是gzip压缩的。使用zlib库,我想尝试解压缩x - 如果成功,函数将返回压缩的String。如果不是(即x不是gzip压缩的)我想简单地返回x

如果GZip.decompress生成error,如果应用于非gzip字符串,我可以使用catch或类似的,但我特别要求使用{{{ 1}}错误处理机制。

如何编写一个具有前述特征的zlib函数?我希望decompressIfPossible :: ByteString -> ByteString代表错误或解压缩结果。

注意:这个问题故意不会显示研究工作,因为它立即以Q& A风格的方式回答。

1 个答案:

答案 0 :(得分:1)

此处需要使用的zlib函数称为decompressWithErrors。它的值是递归DecompressStream数据结构,您可以使用v:fromDecompressStream

将其折叠为ByteString

以下是如何编写您要求的函数的完整示例:

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标头。