我有一个字符串x
可能会或可能不会是gzip压缩。 使用zlib
图书馆,我想尝试解压x
-如果成功,该函数将返回压缩字符串。 如果不是(即x
不是用gzip压缩的),我想简单的返回x
。
作为GZip.decompress
产生一个error
,如果适用于非gzip的字符串,我可以用catch
或相似,但我专门要求使用该解决方案zlib
错误处理机制。
我怎么可以编写一个函数,说decompressIfPossible :: ByteString -> ByteString
已经先前描述的特征? 我宁愿一个Either String ByteString
来表示任何错误或减压的结果。
注意:这个问题故意不显示的研究工作,因为它是在一个Q&A式地立即回答。
从功能zlib
你需要在这里使用被称为decompressWithErrors
。 它的值是递归DecompressStream
数据结构,可以折叠成一个ByteString
用v: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头,其自动检测。