我有一个字符串x
,它可能是也可能不是gzip压缩的。使用zlib
库,我想尝试解压缩x
- 如果成功,函数将返回压缩的String。如果不是(即x
不是gzip压缩的)我想简单地返回x
。
如果GZip.decompress
生成error
,如果应用于非gzip字符串,我可以使用catch
或类似的,但我特别要求使用{{{ 1}}错误处理机制。
如何编写一个具有前述特征的zlib
函数?我希望decompressIfPossible :: ByteString -> ByteString
代表错误或解压缩结果。
注意:这个问题故意不会显示研究工作,因为它立即以Q& A风格的方式回答。
答案 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标头。