diff --git a/libraries-apache-commons-2/README.md b/libraries-apache-commons-2/README.md
new file mode 100644
index 0000000000..7f91a737d5
--- /dev/null
+++ b/libraries-apache-commons-2/README.md
@@ -0,0 +1,7 @@
+## Apache Commons
+
+This module contains articles about Apache Commons libraries.
+
+### Relevant articles
+
+- More articles: [[<--prev]](../libraries-apache-commons)
\ No newline at end of file
diff --git a/libraries-apache-commons-2/log4j.properties b/libraries-apache-commons-2/log4j.properties
new file mode 100644
index 0000000000..2173c5d96f
--- /dev/null
+++ b/libraries-apache-commons-2/log4j.properties
@@ -0,0 +1 @@
+log4j.rootLogger=INFO, stdout
diff --git a/libraries-apache-commons-2/pom.xml b/libraries-apache-commons-2/pom.xml
new file mode 100644
index 0000000000..d771aac9ab
--- /dev/null
+++ b/libraries-apache-commons-2/pom.xml
@@ -0,0 +1,39 @@
+
+
+ 4.0.0
+ libraries-apache-commons-2
+ libraries-apache-commons-2
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+
+
+ org.apache.commons
+ commons-compress
+ ${commons-compress.version}
+
+
+ org.apache.ant
+ ant
+ ${ant.version}
+
+
+ org.apache.commons
+ commons-vfs2
+ ${commons-vfs2.version}
+
+
+
+
+ 1.23.0
+ 1.10.13
+ 2.9.0
+
+
+
\ No newline at end of file
diff --git a/libraries-apache-commons-2/src/main/java/com/baeldung/commons/untar/Resources.java b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/untar/Resources.java
new file mode 100644
index 0000000000..15e71eb156
--- /dev/null
+++ b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/untar/Resources.java
@@ -0,0 +1,14 @@
+package com.baeldung.commons.untar;
+
+import java.io.InputStream;
+
+public interface Resources {
+
+ static InputStream tarFile() {
+ return Resources.class.getResourceAsStream("/untar/test.tar");
+ }
+
+ static InputStream tarGzFile() {
+ return Resources.class.getResourceAsStream("/untar/test.tar.gz");
+ }
+}
\ No newline at end of file
diff --git a/libraries-apache-commons-2/src/main/java/com/baeldung/commons/untar/TarExtractor.java b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/untar/TarExtractor.java
new file mode 100644
index 0000000000..73a54bba44
--- /dev/null
+++ b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/untar/TarExtractor.java
@@ -0,0 +1,39 @@
+package com.baeldung.commons.untar;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+public abstract class TarExtractor {
+
+ private InputStream tarStream;
+ private boolean gzip;
+ private Path destination;
+
+ protected TarExtractor(InputStream in, boolean gzip, Path destination) throws IOException {
+ this.tarStream = in;
+ this.gzip = gzip;
+ this.destination = destination;
+
+ Files.createDirectories(destination);
+ }
+
+ protected TarExtractor(Path tarFile, Path destination) throws IOException {
+ this(Files.newInputStream(tarFile), tarFile.endsWith("gz"), destination);
+ }
+
+ public Path getDestination() {
+ return destination;
+ }
+
+ public InputStream getTarStream() {
+ return tarStream;
+ }
+
+ public boolean isGzip() {
+ return gzip;
+ }
+
+ public abstract void untar() throws IOException;
+}
\ No newline at end of file
diff --git a/libraries-apache-commons-2/src/main/java/com/baeldung/commons/untar/impl/TarExtractorAnt.java b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/untar/impl/TarExtractorAnt.java
new file mode 100644
index 0000000000..5bb4d74beb
--- /dev/null
+++ b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/untar/impl/TarExtractorAnt.java
@@ -0,0 +1,37 @@
+package com.baeldung.commons.untar.impl;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.util.zip.GZIPInputStream;
+
+import org.apache.tools.tar.TarEntry;
+import org.apache.tools.tar.TarInputStream;
+
+import com.baeldung.commons.untar.TarExtractor;
+
+public class TarExtractorAnt extends TarExtractor {
+
+ public TarExtractorAnt(InputStream in, boolean gzip, Path destination) throws IOException {
+ super(in, gzip, destination);
+ }
+
+ @Override
+ public void untar() throws IOException {
+ try (TarInputStream tar = new TarInputStream(new BufferedInputStream( //
+ isGzip() ? new GZIPInputStream(getTarStream()) : getTarStream()))) {
+ TarEntry entry;
+ while ((entry = tar.getNextEntry()) != null) {
+ Path extractTo = getDestination().resolve(entry.getName());
+ if (entry.isDirectory()) {
+ Files.createDirectories(extractTo);
+ } else {
+ Files.copy(tar, extractTo, StandardCopyOption.REPLACE_EXISTING);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/libraries-apache-commons-2/src/main/java/com/baeldung/commons/untar/impl/TarExtractorCommonsCompress.java b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/untar/impl/TarExtractorCommonsCompress.java
new file mode 100644
index 0000000000..4981426c35
--- /dev/null
+++ b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/untar/impl/TarExtractorCommonsCompress.java
@@ -0,0 +1,38 @@
+package com.baeldung.commons.untar.impl;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
+import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
+
+import com.baeldung.commons.untar.TarExtractor;
+
+public class TarExtractorCommonsCompress extends TarExtractor {
+
+ public TarExtractorCommonsCompress(InputStream in, boolean gzip, Path destination) throws IOException {
+ super(in, gzip, destination);
+ }
+
+ @Override
+ public void untar() throws IOException {
+ try (BufferedInputStream inputStream = new BufferedInputStream(getTarStream()); //
+ TarArchiveInputStream tar = new TarArchiveInputStream( //
+ isGzip() ? new GzipCompressorInputStream(inputStream) : inputStream)) {
+ ArchiveEntry entry;
+ while ((entry = tar.getNextEntry()) != null) {
+ Path extractTo = getDestination().resolve(entry.getName());
+ if (entry.isDirectory()) {
+ Files.createDirectories(extractTo);
+ } else {
+ Files.copy(tar, extractTo, StandardCopyOption.REPLACE_EXISTING);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/libraries-apache-commons-2/src/main/java/com/baeldung/commons/untar/impl/TarExtractorVfs.java b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/untar/impl/TarExtractorVfs.java
new file mode 100644
index 0000000000..291fcebfb0
--- /dev/null
+++ b/libraries-apache-commons-2/src/main/java/com/baeldung/commons/untar/impl/TarExtractorVfs.java
@@ -0,0 +1,48 @@
+package com.baeldung.commons.untar.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+
+import org.apache.commons.vfs2.FileContent;
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSystemManager;
+import org.apache.commons.vfs2.FileType;
+import org.apache.commons.vfs2.VFS;
+
+import com.baeldung.commons.untar.TarExtractor;
+
+public class TarExtractorVfs extends TarExtractor {
+
+ public TarExtractorVfs(InputStream in, boolean gzip, Path destination) throws IOException {
+ super(in, gzip, destination);
+ }
+
+ @Override
+ public void untar() throws IOException {
+ Path tmpTar = Files.createTempFile("temp", isGzip() ? ".tar.gz" : ".tar");
+ Files.copy(getTarStream(), tmpTar, StandardCopyOption.REPLACE_EXISTING);
+
+ FileSystemManager fsManager = VFS.getManager();
+ String uri = String.format("%s:file://%s", isGzip() ? "tgz" : "tar", tmpTar);
+ FileObject tar = fsManager.resolveFile(uri);
+
+ for (FileObject entry : tar) {
+ Path extractTo = Paths.get(getDestination().toString(), entry.getName()
+ .getPath());
+
+ if (entry.isReadable() && entry.getType() == FileType.FILE) {
+ Files.createDirectories(extractTo.getParent());
+
+ try (FileContent content = entry.getContent(); InputStream stream = content.getInputStream()) {
+ Files.copy(stream, extractTo, StandardCopyOption.REPLACE_EXISTING);
+ }
+ }
+ }
+
+ Files.delete(tmpTar);
+ }
+}
\ No newline at end of file
diff --git a/libraries-apache-commons-2/src/main/resources/logback.xml b/libraries-apache-commons-2/src/main/resources/logback.xml
new file mode 100644
index 0000000000..7d900d8ea8
--- /dev/null
+++ b/libraries-apache-commons-2/src/main/resources/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libraries-apache-commons-2/src/test/java/com/baeldung/commons/untar/TarExtractorAntUnitTest.java b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/untar/TarExtractorAntUnitTest.java
new file mode 100644
index 0000000000..0b39f49884
--- /dev/null
+++ b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/untar/TarExtractorAntUnitTest.java
@@ -0,0 +1,40 @@
+package com.baeldung.commons.untar;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Stream;
+
+import org.junit.Test;
+
+import com.baeldung.commons.untar.impl.TarExtractorAnt;
+
+public class TarExtractorAntUnitTest {
+
+ @Test
+ public void givenTarFile_whenUntar_thenExtractedToDestination() throws IOException {
+ Path destination = Paths.get("/tmp/ant");
+
+ new TarExtractorAnt(Resources.tarFile(), false, destination).untar();
+
+ try (Stream files = Files.list(destination)) {
+ assertTrue(files.findFirst()
+ .isPresent());
+ }
+ }
+
+ @Test
+ public void givenTarGzFile_whenUntar_thenExtractedToDestination() throws IOException {
+ Path destination = Paths.get("/tmp/ant-gz");
+
+ new TarExtractorAnt(Resources.tarGzFile(), true, destination).untar();
+
+ try (Stream files = Files.list(destination)) {
+ assertTrue(files.findFirst()
+ .isPresent());
+ }
+ }
+}
diff --git a/libraries-apache-commons-2/src/test/java/com/baeldung/commons/untar/TarExtractorCommonsCompressUnitTest.java b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/untar/TarExtractorCommonsCompressUnitTest.java
new file mode 100644
index 0000000000..e9c7d701d3
--- /dev/null
+++ b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/untar/TarExtractorCommonsCompressUnitTest.java
@@ -0,0 +1,40 @@
+package com.baeldung.commons.untar;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.Test;
+
+import com.baeldung.commons.untar.impl.TarExtractorCommonsCompress;
+
+public class TarExtractorCommonsCompressUnitTest {
+
+ @Test
+ public void givenTarFile_whenUntar_thenExtractedToDestination() throws IOException {
+ Path destination = Paths.get("/tmp/commons-compress");
+
+ new TarExtractorCommonsCompress(Resources.tarFile(), false, destination).untar();
+
+ try (Stream files = Files.list(destination)) {
+ assertTrue(files.findFirst()
+ .isPresent());
+ }
+ }
+
+ @Test
+ public void givenTarGzFile_whenUntar_thenExtractedToDestination() throws IOException {
+ Path destination = Paths.get("/tmp/commons-compress-gz");
+
+ new TarExtractorCommonsCompress(Resources.tarGzFile(), true, destination).untar();
+
+ try (Stream files = Files.list(destination)) {
+ assertTrue(files.findFirst()
+ .isPresent());
+ }
+ }
+}
\ No newline at end of file
diff --git a/libraries-apache-commons-2/src/test/java/com/baeldung/commons/untar/TarExtractorVfsUnitTest.java b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/untar/TarExtractorVfsUnitTest.java
new file mode 100644
index 0000000000..d5e9004732
--- /dev/null
+++ b/libraries-apache-commons-2/src/test/java/com/baeldung/commons/untar/TarExtractorVfsUnitTest.java
@@ -0,0 +1,40 @@
+package com.baeldung.commons.untar;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Stream;
+
+import org.junit.Test;
+
+import com.baeldung.commons.untar.impl.TarExtractorVfs;
+
+public class TarExtractorVfsUnitTest {
+
+ @Test
+ public void givenTarFile_whenUntar_thenExtractedToDestination() throws IOException {
+ Path destination = Paths.get("/tmp/vfs");
+
+ new TarExtractorVfs(Resources.tarFile(), false, destination).untar();
+
+ try (Stream files = Files.list(destination)) {
+ assertTrue(files.findFirst()
+ .isPresent());
+ }
+ }
+
+ @Test
+ public void givenTarGzFile_whenUntar_thenExtractedToDestination() throws IOException {
+ Path destination = Paths.get("/tmp/vfs-gz");
+
+ new TarExtractorVfs(Resources.tarGzFile(), true, destination).untar();
+
+ try (Stream files = Files.list(destination)) {
+ assertTrue(files.findFirst()
+ .isPresent());
+ }
+ }
+}
\ No newline at end of file
diff --git a/libraries-apache-commons-2/src/test/resources/untar/test.tar b/libraries-apache-commons-2/src/test/resources/untar/test.tar
new file mode 100644
index 0000000000..a0c9e8714f
Binary files /dev/null and b/libraries-apache-commons-2/src/test/resources/untar/test.tar differ
diff --git a/libraries-apache-commons-2/src/test/resources/untar/test.tar.gz b/libraries-apache-commons-2/src/test/resources/untar/test.tar.gz
new file mode 100644
index 0000000000..99bc3ec933
Binary files /dev/null and b/libraries-apache-commons-2/src/test/resources/untar/test.tar.gz differ
diff --git a/libraries-apache-commons/README.md b/libraries-apache-commons/README.md
index aceea3282a..9623ecca2f 100644
--- a/libraries-apache-commons/README.md
+++ b/libraries-apache-commons/README.md
@@ -13,4 +13,5 @@ This module contains articles about Apache Commons libraries.
- [Apache Commons BeanUtils](https://www.baeldung.com/apache-commons-beanutils)
- [Histograms with Apache Commons Frequency](https://www.baeldung.com/apache-commons-frequency)
- [An Introduction to Apache Commons Lang 3](https://www.baeldung.com/java-commons-lang-3)
-- [Differences Between the Java WatchService API and the Apache Commons IO Monitor Library](https://www.baeldung.com/java-watchservice-vs-apache-commons-io-monitor-library)
\ No newline at end of file
+- [Differences Between the Java WatchService API and the Apache Commons IO Monitor Library](https://www.baeldung.com/java-watchservice-vs-apache-commons-io-monitor-library)
+More articles: [[next-->]](../libraries-apache-commons-2)
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 0091f57913..6d566549ef 100644
--- a/pom.xml
+++ b/pom.xml
@@ -867,6 +867,7 @@
libraries-6
libraries-apache-commons
+ libraries-apache-commons-2
libraries-apache-commons-collections
libraries-apache-commons-io
libraries-data-2
@@ -1135,6 +1136,7 @@
libraries-5
libraries-6
libraries-apache-commons
+ libraries-apache-commons-2
libraries-apache-commons-collections
libraries-apache-commons-io
libraries-data-2