From 4b5e5192d987fa5fac5101b854071edaa59695d6 Mon Sep 17 00:00:00 2001 From: Ulisses Lima Date: Mon, 8 Apr 2024 03:17:59 -0300 Subject: [PATCH] BAEL 7619 - Intro to the Apache Commons Compress Project (#16220) * matcher.appendReplacement() takes a StringBuffer, not StringBuilder * First draft * review 1 --- libraries-apache-commons-2/pom.xml | 14 +- .../commons/compress/CompressUtils.java | 119 +++++++++++++++ .../convertunicode/UnicodeConverterUtil.java | 6 +- .../compress/CompressUtilsUnitTest.java | 135 ++++++++++++++++++ .../commons/compress/TestResources.java | 25 ++++ .../test/resources/compress/archive.tar.gz | Bin 0 -> 226 bytes .../src/test/resources/compress/new.txt | 2 + 7 files changed, 297 insertions(+), 4 deletions(-) create mode 100644 libraries-apache-commons-2/src/main/java/com/baeldung/commons/compress/CompressUtils.java create mode 100644 libraries-apache-commons-2/src/test/java/com/baeldung/commons/compress/CompressUtilsUnitTest.java create mode 100644 libraries-apache-commons-2/src/test/java/com/baeldung/commons/compress/TestResources.java create mode 100644 libraries-apache-commons-2/src/test/resources/compress/archive.tar.gz create mode 100644 libraries-apache-commons-2/src/test/resources/compress/new.txt diff --git a/libraries-apache-commons-2/pom.xml b/libraries-apache-commons-2/pom.xml index c555b83273..0f00bf5d84 100644 --- a/libraries-apache-commons-2/pom.xml +++ b/libraries-apache-commons-2/pom.xml @@ -44,15 +44,27 @@ ${mockftpserver.version} test + + org.tukaani + xz + ${xz.version} + + + com.github.luben + zstd-jni + ${zstd-jni.version} + - 1.23.0 + 1.26.1 1.10.13 2.9.0 1.10.0 3.6 2.7.1 + 1.9 + 1.5.5-11 \ No newline at end of file diff --git a/libraries-apache-commons-2/src/main/java/com/baeldung/commons/compress/CompressUtils.java b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/compress/CompressUtils.java new file mode 100644 index 0000000000..796b3fd22b --- /dev/null +++ b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/compress/CompressUtils.java @@ -0,0 +1,119 @@ +package com.baeldung.commons.compress; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.zip.Deflater; +import java.util.zip.ZipEntry; + +import org.apache.commons.compress.archivers.ArchiveEntry; +import org.apache.commons.compress.archivers.ArchiveException; +import org.apache.commons.compress.archivers.ArchiveInputStream; +import org.apache.commons.compress.archivers.ArchiveOutputStream; +import org.apache.commons.compress.archivers.ArchiveStreamFactory; +import org.apache.commons.compress.archivers.examples.Archiver; +import org.apache.commons.compress.archivers.examples.Expander; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; +import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; +import org.apache.commons.compress.compressors.CompressorException; +import org.apache.commons.compress.compressors.CompressorInputStream; +import org.apache.commons.compress.compressors.CompressorOutputStream; +import org.apache.commons.compress.compressors.CompressorStreamFactory; +import org.apache.commons.compress.utils.FileNameUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; + +public class CompressUtils { + + private CompressUtils() { + } + + public static void archive(Path directory, Path destination) throws IOException, ArchiveException { + String format = FileNameUtils.getExtension(destination); + new Archiver().create(format, destination, directory); + } + + public static void archiveAndCompress(String directory, Path destination) throws IOException, ArchiveException, CompressorException { + archiveAndCompress(Paths.get(directory), destination); + } + + public static void archiveAndCompress(Path directory, Path destination) throws IOException, ArchiveException, CompressorException { + String compressionFormat = FileNameUtils.getExtension(destination); + String archiveFormat = FilenameUtils.getExtension(destination.getFileName() + .toString() + .replace("." + compressionFormat, "")); + + try (OutputStream archive = Files.newOutputStream(destination); + BufferedOutputStream archiveBuffer = new BufferedOutputStream(archive); + CompressorOutputStream compressor = new CompressorStreamFactory().createCompressorOutputStream(compressionFormat, archiveBuffer); + ArchiveOutputStream archiver = new ArchiveStreamFactory().createArchiveOutputStream(archiveFormat, compressor)) { + new Archiver().create(archiver, directory); + } + } + + public static void decompress(Path file, Path destination) throws IOException, ArchiveException, CompressorException { + decompress(Files.newInputStream(file), destination); + } + + public static void decompress(InputStream file, Path destination) throws IOException, ArchiveException, CompressorException { + try (InputStream in = file; + BufferedInputStream inputBuffer = new BufferedInputStream(in); + OutputStream out = Files.newOutputStream(destination); + CompressorInputStream decompressor = new CompressorStreamFactory().createCompressorInputStream(inputBuffer)) { + IOUtils.copy(decompressor, out); + } + } + + public static void extract(Path archive, Path destination) throws IOException, ArchiveException, CompressorException { + new Expander().expand(archive, destination); + } + + public static void compressFile(Path file, Path destination) throws IOException, CompressorException { + String format = FileNameUtils.getExtension(destination); + + try (OutputStream out = Files.newOutputStream(destination); + BufferedOutputStream buffer = new BufferedOutputStream(out); + CompressorOutputStream compressor = new CompressorStreamFactory().createCompressorOutputStream(format, buffer)) { + IOUtils.copy(Files.newInputStream(file), compressor); + } + } + + public static void zip(Path file, Path destination) throws IOException { + try (InputStream input = Files.newInputStream(file); + OutputStream output = Files.newOutputStream(destination); + ZipArchiveOutputStream archive = new ZipArchiveOutputStream(output)) { + archive.setLevel(Deflater.BEST_COMPRESSION); + archive.setMethod(ZipEntry.DEFLATED); + + archive.putArchiveEntry(new ZipArchiveEntry(file.getFileName() + .toString())); + IOUtils.copy(input, archive); + archive.closeArchiveEntry(); + } + } + + public static void extractOne(Path archivePath, String fileName, Path destinationDirectory) throws IOException, ArchiveException { + try (InputStream input = Files.newInputStream(archivePath); + BufferedInputStream buffer = new BufferedInputStream(input); + ArchiveInputStream archive = new ArchiveStreamFactory().createArchiveInputStream(buffer)) { + + ArchiveEntry entry; + while ((entry = archive.getNextEntry()) != null) { + if (entry.getName() + .equals(fileName)) { + Path outFile = destinationDirectory.resolve(fileName); + Files.createDirectories(outFile.getParent()); + try (OutputStream os = Files.newOutputStream(outFile)) { + IOUtils.copy(archive, os); + } + break; + } + } + } + } +} \ No newline at end of file diff --git a/libraries-apache-commons-2/src/main/java/com/baeldung/commons/convertunicode/UnicodeConverterUtil.java b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/convertunicode/UnicodeConverterUtil.java index c788f6ee61..997c5b61ff 100644 --- a/libraries-apache-commons-2/src/main/java/com/baeldung/commons/convertunicode/UnicodeConverterUtil.java +++ b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/convertunicode/UnicodeConverterUtil.java @@ -1,10 +1,10 @@ package com.baeldung.commons.convertunicode; -import org.apache.commons.text.StringEscapeUtils; - import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.commons.text.StringEscapeUtils; + public class UnicodeConverterUtil { public static String decodeWithApacheCommons(String input) { @@ -15,7 +15,7 @@ public class UnicodeConverterUtil { Pattern pattern = Pattern.compile("\\\\u[0-9a-fA-F]{4}"); Matcher matcher = pattern.matcher(input); - StringBuilder decodedString = new StringBuilder(); + StringBuffer decodedString = new StringBuffer(); while (matcher.find()) { String unicodeSequence = matcher.group(); diff --git a/libraries-apache-commons-2/src/test/java/com/baeldung/commons/compress/CompressUtilsUnitTest.java b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/compress/CompressUtilsUnitTest.java new file mode 100644 index 0000000000..9bdaf0dfd4 --- /dev/null +++ b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/compress/CompressUtilsUnitTest.java @@ -0,0 +1,135 @@ +package com.baeldung.commons.compress; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.apache.commons.compress.archivers.ArchiveException; +import org.apache.commons.compress.compressors.CompressorException; +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +class CompressUtilsUnitTest { + + static Path TMP; + static String ZIP_FILE = "new.txt.zip"; + static String COMPRESSED_FILE = "new.txt.gz"; + static String DECOMPRESSED_FILE = "decompressed-file.txt"; + static String DECOMPRESSED_ARCHIVE = "decompressed-archive.tar"; + static String COMPRESSED_ARCHIVE = "archive.tar.gz"; + static String MODIFIED_ARCHIVE = "modified-archive.tar"; + static String EXTRACTED_DIR = "extracted"; + + @BeforeAll + static void setup() throws IOException { + TMP = Files.createTempDirectory("compress-test") + .toAbsolutePath(); + } + + @AfterAll + static void destroy() throws IOException { + FileUtils.deleteDirectory(TMP.toFile()); + } + + @Test + @Order(1) + void givenFile_whenCompressing_thenCompressed() throws IOException, CompressorException, URISyntaxException { + Path destination = TMP.resolve(COMPRESSED_FILE); + + CompressUtils.compressFile(TestResources.testFile(), destination); + + assertTrue(Files.isRegularFile(destination)); + } + + @Test + @Order(2) + void givenFile_whenZipping_thenZipFileCreated() throws IOException, URISyntaxException { + Path destination = TMP.resolve(ZIP_FILE); + + CompressUtils.zip(TestResources.testFile(), destination); + + assertTrue(Files.isRegularFile(destination)); + } + + @Test + @Order(3) + void givenCompressedArchive_whenDecompressing_thenArchiveAvailable() throws IOException, ArchiveException, CompressorException { + Path destination = TMP.resolve(DECOMPRESSED_ARCHIVE); + + CompressUtils.decompress(TestResources.compressedArchive(), destination); + + assertTrue(Files.isRegularFile(destination)); + } + + @Test + @Order(4) + void givenCompressedFile_whenDecompressing_thenFileAvailable() throws IOException, ArchiveException, CompressorException { + Path destination = TMP.resolve(DECOMPRESSED_FILE); + + CompressUtils.decompress(TMP.resolve(COMPRESSED_FILE), destination); + + assertTrue(Files.isRegularFile(destination)); + } + + @Test + @Order(5) + void givenDecompressedArchive_whenUnarchiving_thenFilesAvailable() throws IOException, ArchiveException, CompressorException { + Path destination = TMP.resolve(EXTRACTED_DIR); + + CompressUtils.extract(TMP.resolve(DECOMPRESSED_ARCHIVE), destination); + + assertTrue(Files.isDirectory(destination)); + } + + @Test + @Order(6) + void givenDirectory_whenArchivingAndCompressing_thenCompressedArchiveAvailable() throws IOException, ArchiveException, CompressorException { + Path destination = TMP.resolve(COMPRESSED_ARCHIVE); + + CompressUtils.archiveAndCompress(TMP.resolve(EXTRACTED_DIR), destination); + + assertTrue(Files.isRegularFile(destination)); + } + + @Test + @Order(7) + void givenExistingArchive_whenAddingSingleEntry_thenArchiveModified() throws IOException, ArchiveException, CompressorException, URISyntaxException { + Path archive = TMP.resolve(DECOMPRESSED_ARCHIVE); + Path newArchive = TMP.resolve(MODIFIED_ARCHIVE); + Path tmpDir = TMP.resolve(newArchive + "-tmpd"); + + Path newEntry = TestResources.testFile(); + + CompressUtils.extract(archive, tmpDir); + assertTrue(Files.isDirectory(tmpDir)); + + Files.copy(newEntry, tmpDir.resolve(newEntry.getFileName())); + CompressUtils.archive(tmpDir, newArchive); + assertTrue(Files.isRegularFile(newArchive)); + + FileUtils.deleteDirectory(tmpDir.toFile()); + Files.delete(archive); + Files.move(newArchive, archive); + assertTrue(Files.isRegularFile(archive)); + } + + @Test + @Order(8) + void givenExistingArchive_whenExtractingSingleEntry_thenFileExtracted() throws IOException, ArchiveException { + Path archive = TMP.resolve(DECOMPRESSED_ARCHIVE); + String targetFile = "sub/other.txt"; + + CompressUtils.extractOne(archive, targetFile, TMP); + + assertTrue(Files.isRegularFile(TMP.resolve(targetFile))); + } +} diff --git a/libraries-apache-commons-2/src/test/java/com/baeldung/commons/compress/TestResources.java b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/compress/TestResources.java new file mode 100644 index 0000000000..6e1f4129cf --- /dev/null +++ b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/compress/TestResources.java @@ -0,0 +1,25 @@ +package com.baeldung.commons.compress; + +import java.io.InputStream; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; + +public interface TestResources { + + String DIR = "/compress/"; + + static InputStream compressedArchive() { + return TestResources.class.getResourceAsStream(DIR + CompressUtilsUnitTest.COMPRESSED_ARCHIVE); + } + + static Path testFile() throws URISyntaxException { + URL resource = TestResources.class.getResource(DIR + "new.txt"); + if (resource == null) { + throw new IllegalArgumentException("file not found!"); + } else { + return Paths.get(resource.toURI()); + } + } +} \ No newline at end of file diff --git a/libraries-apache-commons-2/src/test/resources/compress/archive.tar.gz b/libraries-apache-commons-2/src/test/resources/compress/archive.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..cdb6fd3fd4ba0f771f1bcbaf5ead212d7528db9d GIT binary patch literal 226 zcmV<803H7yiwFP!00000|Lv2}3c@f9Mfbd~$QNj8)9rhvR-JBEn^vb^Zzl{?5MQi< z_Pm5Nf!uPr?5E=_GKhqwQhD1^eWCnOb<3{-4kJ)T`{u5*!Ypg=5$p8K!p!G9$QGr&lC?)Y>6gY~fY^=t!EYmQr3 zm@Z%YcE?~2+Co2Ws`DwIn`QoOt%>*JG`on=zw$EwQV#h?>fZ$sru=_|##r4#y<^{o cjE4@mc2Kq2rMM>&iNr5+0ZH~$y#NjX07EZsH~;_u literal 0 HcmV?d00001 diff --git a/libraries-apache-commons-2/src/test/resources/compress/new.txt b/libraries-apache-commons-2/src/test/resources/compress/new.txt new file mode 100644 index 0000000000..f207b5eb40 --- /dev/null +++ b/libraries-apache-commons-2/src/test/resources/compress/new.txt @@ -0,0 +1,2 @@ +lorem ipsum +dolor sit amet