blob: eb8970c15a5817917592a3aad7d321588401186e [file]
= Zip File DataFormat
:doctitle: Zip File
:shortname: zipFile
:artifactid: camel-zipfile
:description: Compression and decompress streams using java.util.zip.Zip*Stream
:since: 2.11
:supportlevel: Stable
:tabs-sync-option:
*Since Camel {since}*
The Zip File Data Format is a message compression and decompression format.
Messages can be marshaled (compressed) to Zip files containing a single entry, and Zip files containing a single
entry can be unmarshalled (decompressed) to the original file contents.
This data format supports ZIP64, as long as Java 7 or later is being used.
== ZipFile Options
// dataformat options: START
include::partial$dataformat-options.adoc[]
// dataformat options: END
== Marshal
In this example, we marshal a regular text/XML payload to a compressed
payload using Zip file compression, and send it to an ActiveMQ queue
called MY_QUEUE.
[tabs]
====
Java::
+
[source,java]
----
from("direct:start")
.marshal().zipFile()
.to("activemq:queue:MY_QUEUE");
----
XML::
+
[source,xml]
----
<route>
<from uri="direct:start"/>
<marshal>
<zipFile/>
</marshal>
<to uri="activemq:queue:MY_QUEUE"/>
</route>
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:start
steps:
- marshal:
zipFile: {}
- to:
uri: activemq:queue:MY_QUEUE
----
====
The name of the Zip entry inside the created Zip file is based on the
incoming `CamelFileName` message header, which is the standard message
header used by the file component. Additionally, the
outgoing `CamelFileName` message header is automatically set to the
value of the incoming `CamelFileName` message header, with the ".zip"
suffix. So, for example, if the following route finds a file named
"test.txt" in the input directory, the output will be a Zip file named
"test.txt.zip" containing a single Zip entry named "test.txt":
[tabs]
====
Java::
+
[source,java]
----
from("file:input/directory?antInclude=*/.txt")
.marshal().zipFile()
.to("file:output/directory");
----
XML::
+
[source,xml]
----
<route>
<from uri="file:input/directory?antInclude=*/.txt"/>
<marshal>
<zipFile/>
</marshal>
<to uri="file:output/directory"/>
</route>
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: file:input/directory
parameters:
antInclude: "*/.txt"
steps:
- marshal:
zipFile: {}
- to:
uri: file:output/directory
----
====
If there is no incoming `CamelFileName` message header, (for example, if
the file component is not the consumer), then the
message ID is used by default.
Since the message ID is normally a unique generated ID, you will end up with filenames like
`ID-MACHINENAME-2443-1211718892437-1-0.zip`. If you want to override
this behavior, then you can set the value of the `CamelFileName` header
explicitly in your route:
[tabs]
====
Java::
+
[source,java]
----
from("direct:start")
.setHeader(Exchange.FILE_NAME, constant("report.txt"))
.marshal().zipFile()
.to("file:output/directory");
----
XML::
+
[source,xml]
----
<route>
<from uri="direct:start"/>
<setHeader name="CamelFileName">
<constant>report.txt</constant>
</setHeader>
<marshal>
<zipFile/>
</marshal>
<to uri="file:output/directory"/>
</route>
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:start
steps:
- setHeader:
name: CamelFileName
constant: report.txt
- marshal:
zipFile: {}
- to:
uri: file:output/directory
----
====
This route would result in a Zip file named "report.txt.zip" in the
output directory, containing a single Zip entry named "report.txt".
== Unmarshal
In this example we unmarshal a Zip file payload from an ActiveMQ queue
called MY_QUEUE to its original format, and forward it for processing to
the `UnZippedMessageProcessor`.
._Java-only: inline Processor class_
[source,java]
----
from("activemq:queue:MY_QUEUE")
.unmarshal().zipFile()
.process(new UnZippedMessageProcessor());
----
If the zip file has more than one entry, the usingIterator option of
ZipFileDataFormat to be true, and you can use splitter to do the further
work.
._Java-only: Java programmatic data format configuration_
[source,java]
----
ZipFileDataFormat zipFile = new ZipFileDataFormat();
zipFile.setUsingIterator(true);
from("file:src/test/resources/org/apache/camel/dataformat/zipfile/?delay=1000&noop=true")
.unmarshal(zipFile)
.split(bodyAs(Iterator.class)).streaming()
.process(new UnZippedMessageProcessor())
.end();
----
Or you can use the ZipSplitter as an expression for splitter directly like this:
._Java-only: Java ZipSplitter class_
[source,java]
----
from("file:src/test/resources/org/apache/camel/dataformat/zipfile?delay=1000&noop=true")
.split(new ZipSplitter()).streaming()
.process(new UnZippedMessageProcessor())
.end();
----
[IMPORTANT]
====
You *cannot* use ZipSplitter in _parallel_ mode with the splitter.
====
== Aggregate
[NOTE]
====
Please note that this aggregation strategy requires eager completion check to work properly.
====
In this example, we aggregate all text files found in the input directory
into a single Zip file that is stored in the output directory.
._Java-only: Java ZipAggregationStrategy class_
[source,java]
----
from("file:input/directory?antInclude=*/.txt")
.aggregate(constant(true), new ZipAggregationStrategy())
.completionFromBatchConsumer().eagerCheckCompletion()
.to("file:output/directory");
----
The outgoing `CamelFileName` message header is created using
java.io.File.createTempFile, with the ".zip" suffix. If you want to
override this behavior, then you can set the value of
the `CamelFileName` header explicitly in your route:
._Java-only: Java ZipAggregationStrategy class_
[source,java]
----
from("file:input/directory?antInclude=*/.txt")
.aggregate(constant(true), new ZipAggregationStrategy())
.completionFromBatchConsumer().eagerCheckCompletion()
.setHeader(Exchange.FILE_NAME, constant("reports.zip"))
.to("file:output/directory");
----
When the zip file already has an entry with the same name, for example two files `orders.csv` from different folders
of a recursive file consumer, the later entry is added with a number before its extension (`orders (1).csv`,
`orders (2).csv`, ...), so no content is lost. Use `preserveFolderStructure` to keep the folders in the entry names.
== Dependencies
To use Zip files in your camel routes, you need to add a dependency on
*camel-zipfile* which implements this data format.
If you use Maven you can add the following to your `pom.xml`,
substituting the version number for the latest & greatest release (see
the download page for the latest versions).
[source,xml]
----
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-zipfile</artifactId>
<version>x.x.x</version>
<!-- use the same version as your Camel core version -->
</dependency>
----