From 37b2918398b16e7dea8990410f5e9143cfcc0fb4 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Tue, 5 Aug 2025 08:01:46 +1000 Subject: [PATCH 1/3] fix: use buffered writes for performance When not using STORED entries use a BufferedOutputStream to avoid lots of small writes to the file system. Testing this with a 300mb jar build I see the total build time going from 40s to 30s. Note that it is not possible to do this with STORED entries as the implementation requires a RandomAccessFile to update the CRC after write. --- src/docs/changes/README.md | 3 +++ .../gradle/plugins/shadow/internal/DefaultZipCompressor.groovy | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index a58a1f91d..f90f0bae4 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -3,6 +3,9 @@ ## [Unreleased] +**Changed** + +- Use BufferedOutputStream when writing the Zip file to improve performance. ([#1579](https://github.com/GradleUp/shadow/pull/1579)) ## [v8.3.8] (2025-07-01) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy index 829ab294c..7bab009e3 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy @@ -30,7 +30,7 @@ class DefaultZipCompressor implements ZipCompressor { @Override ZipOutputStream createArchiveOutputStream(File destination) { try { - ZipOutputStream zipOutputStream = new ZipOutputStream(destination) + ZipOutputStream zipOutputStream = entryCompressionMethod == java.util.zip.ZipOutputStream.STORED ? new ZipOutputStream(destination) : new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(destination))) zipOutputStream.setUseZip64(zip64Mode) zipOutputStream.setMethod(entryCompressionMethod) return zipOutputStream From 02e821f85c7097eb551471941bf683da4fd8ccd4 Mon Sep 17 00:00:00 2001 From: Goooler Date: Tue, 5 Aug 2025 09:39:18 +0800 Subject: [PATCH 2/3] Cleanup --- src/docs/changes/README.md | 2 +- .../plugins/shadow/internal/DefaultZipCompressor.groovy | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/docs/changes/README.md b/src/docs/changes/README.md index f90f0bae4..5fb6e527a 100644 --- a/src/docs/changes/README.md +++ b/src/docs/changes/README.md @@ -5,7 +5,7 @@ **Changed** -- Use BufferedOutputStream when writing the Zip file to improve performance. ([#1579](https://github.com/GradleUp/shadow/pull/1579)) +- Use `BufferedOutputStream` when writing the Zip file to improve performance. ([#1579](https://github.com/GradleUp/shadow/pull/1579)) ## [v8.3.8] (2025-07-01) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy index 7bab009e3..564ca13be 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy @@ -30,7 +30,10 @@ class DefaultZipCompressor implements ZipCompressor { @Override ZipOutputStream createArchiveOutputStream(File destination) { try { - ZipOutputStream zipOutputStream = entryCompressionMethod == java.util.zip.ZipOutputStream.STORED ? new ZipOutputStream(destination) : new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(destination))) + ZipOutputStream zipOutputStream = entryCompressionMethod == ZipOutputStream.STORED ? + // It is not possible to do this with STORED entries as the implementation requires a RandomAccessFile to update the CRC after write. + new ZipOutputStream(destination) : + new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(destination))) zipOutputStream.setUseZip64(zip64Mode) zipOutputStream.setMethod(entryCompressionMethod) return zipOutputStream From 5c08e465b55fb90c84c91951127fd5aff201c441 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Tue, 5 Aug 2025 09:42:36 +0800 Subject: [PATCH 3/3] Update src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy --- .../gradle/plugins/shadow/internal/DefaultZipCompressor.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy index 564ca13be..1e6dfa8b0 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/DefaultZipCompressor.groovy @@ -31,8 +31,8 @@ class DefaultZipCompressor implements ZipCompressor { ZipOutputStream createArchiveOutputStream(File destination) { try { ZipOutputStream zipOutputStream = entryCompressionMethod == ZipOutputStream.STORED ? - // It is not possible to do this with STORED entries as the implementation requires a RandomAccessFile to update the CRC after write. new ZipOutputStream(destination) : + // It is not possible to do this with STORED entries as the implementation requires a RandomAccessFile to update the CRC after write. new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(destination))) zipOutputStream.setUseZip64(zip64Mode) zipOutputStream.setMethod(entryCompressionMethod)