Created
December 11, 2020 14:57
-
-
Save BaptisteGarcin/74b36d451aeacd0cac2dd5d2e9c0e98b to your computer and use it in GitHub Desktop.
InputStream to .zip in kotlin (GZIPInputStream, GZIPOutputStream + PipedInputStream, PipedOutputStream)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Inspired from https://gist.github.com/xis19/41999145269e4aa398aa354e129e507c | |
// Use externally with GzipUtils.compress(yourInputStream) | |
@Component | |
object GzipUtils { | |
private const val BUFFER_SIZE_BYTES = 512 * 1024 | |
private val gzipExecutor = Executors.newCachedThreadPool(CustomizableThreadFactory("gzip-thread-")) | |
@Volatile | |
private var isShuttingDown = false | |
/** | |
* Compresses the input data using GZip and outputs the compressed data. | |
* | |
* @param input | |
* An [InputStream] containing the input raw data. | |
* | |
* @return An [InputStream] to the compressed data. | |
*/ | |
fun compress(input: InputStream): InputStream { | |
checkShutdown() | |
val compressedDataStream = PipedInputStream(BUFFER_SIZE_BYTES) | |
gzipExecutor.submit { | |
logger.debug("About to compress input data using gzip asynchronously...") | |
val compressionOutput = PipedOutputStream(compressedDataStream) | |
val gzipout: OutputStream = object : GZIPOutputStream(compressionOutput) { | |
init { | |
def.setLevel(Deflater.BEST_COMPRESSION) | |
} | |
} | |
try { | |
input.copyTo(gzipout, BUFFER_SIZE_BYTES) | |
logger.error("Successfully compressed input data using gzip.") | |
} catch (e: IOException) { | |
logger.error("Failed to compress input data.", e) | |
} finally { | |
try { | |
gzipout.close() | |
} catch (e: IOException) { | |
logger.error("Failed to close gzip output stream.", e) | |
} | |
} | |
} | |
return compressedDataStream | |
} | |
/** | |
* Decompresses the input data using GZip and outputs the decompressed data. | |
* | |
* @param input | |
* An [InputStream] containing the input compressed data. | |
* | |
* @return An [InputStream] to the decompressed raw data. | |
* | |
* @throws IOException | |
* Error during decompression | |
*/ | |
@Throws(IOException::class) | |
fun decompress(input: InputStream): InputStream { | |
checkShutdown() | |
val decompressedDataStream = PipedInputStream() | |
val decompressionOutput = PipedOutputStream(decompressedDataStream) | |
gzipExecutor.submit { | |
logger.debug("About to decompress input data using gzip asynchronously...") | |
val gzipCompressedDataStream = GZIPInputStream(input) | |
try { | |
gzipCompressedDataStream.copyTo(decompressionOutput, BUFFER_SIZE_BYTES) | |
logger.debug("Successfully decompressed input data using gzip.") | |
} catch (e: IOException) { | |
logger.error("Failed to decompress input data.", e) | |
} finally { | |
try { | |
decompressionOutput.close() | |
} catch (e: IOException) { | |
logger.error("Failed to close piped output stream.", e) | |
} | |
try { | |
gzipCompressedDataStream.close() | |
} catch (e: IOException) { | |
logger.error("Failed to close gzip input stream.", e) | |
} | |
} | |
} | |
return decompressedDataStream | |
} | |
private fun checkShutdown() { | |
if (isShuttingDown) { | |
throw RejectedExecutionException("Gzip compression/decompression executor has shutdown.") | |
} | |
} | |
@PreDestroy | |
fun shutdown() { | |
if (gzipExecutor.isShutdown) { | |
return | |
} | |
isShuttingDown = true | |
gzipExecutor.shutdownNow() | |
try { | |
gzipExecutor.awaitTermination(30, TimeUnit.SECONDS) | |
logger.debug("Gzip compression/decompression executor has shutdown successfully.") | |
} catch (e: InterruptedException) { | |
logger.error("Waiting for gzip compression/decompression executor shutting down has been interrupted.", e) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment