| = 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> | |
| ---- |