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 0000000000..cdb6fd3fd4
Binary files /dev/null and b/libraries-apache-commons-2/src/test/resources/compress/archive.tar.gz differ
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