2014-02-14 45 views
1

我有一个字符串x可能或不可以gzip压缩。使用zlib库,我想尝试解压缩x - 如果成功,该函数将返回压缩字符串。如果不是(即x不是用gzip压缩的),我想简单地返回x处理哈斯克尔zlib解压缩错误

作为GZip.decompress如果施加到非gzip的字符串产生一个error,我可以使用catch或相似,但我特别要求使用该zlib错误处理机制的溶液。

我该如何编写一个函数,比如decompressIfPossible :: ByteString -> ByteString,它具有上述的特性?我更喜欢Either String ByteString来表示错误或解压缩结果。

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

回答

1

您需要在这里使用的功能从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 [email protected](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头。