The File component provides access to file systems; allowing files to be processed by any other FUSE Mediation Router Components or messages from other components can be saved to disk.
file:fileOrDirectoryName[?options]
or
file://fileOrDirectoryName[?options]
Where fileOrDirectoryName represents the underlying file name. FUSE Mediation Router will determine if fileOrDirectoryName is a file or directory.
![]() | FUSE Mediation Router 2.x |
---|---|
See File2 as the File component in FUSE Mediation Router 2.x has been greatly enhanced, and has a lot of changes and new features. |
![]() | Important Information |
---|---|
See the section "Common gotchas with folder and filenames" below. |
![]() | Timestamp |
---|---|
In FUSE Mediation Router 1.5 or older the file consumer uses an internal timestamp for last polling. This timestamp is used to match for new or changed files: if file modified timestamp > last poll timestamp => file can be consumed. Beware that its not persistent in any way so restarting FUSE Mediation Router will restart the lastpolltime variable and you can potentially consume the same file again. You can disable this algorithm with the new option consumer.timestamp=false or setting the consumer.alwaysConsume=true. FUSE Mediation Router keeps track of consumed files which leads to a memory leak for large number of files in FUSE Mediation Router 1.5.0 and older. This was replaced with a LRU cache in FUSE Mediation Router 1.6.0. Notice: This algorithm has been marked for @deprecation and has been removed in FUSE Mediation Router 2.0. We strongly encourage you to use a different strategy for matching new files: such as deleting or moving the file after processing, then new files is always if there exists a file in the directory to poll. |
![]() | Cannot move/delete file after processing on Windows |
---|---|
There is a potential issue on Windows platform with FUSE Mediation Router 1.5.x.
That it cannot move or delete the file after processing. You should get an exception
thrown. The workaround is to convert the body to a String after consuming using
convertBodyTo: eg
|
Name | Default Value | Description |
---|---|---|
consumer.initialDelay | 1000 | FUSE Mediation Router 1.4: milliseconds before polling the file/directory starts |
consumer.delay | 500 | FUSE Mediation Router 1.4: milliseconds before the next poll of the file/directory |
consumer.useFixedDelay | false | FUSE Mediation Router 1.4: true to use fixed delay between pools, otherwise fixed rate is used. See ScheduledExecutorService in JDK for details. |
consumer.exclusiveReadLock | true | FUSE Mediation Router 1.5: Used by FileConsumer. If set to true FUSE Mediation Router will only poll the files if it has exclusive read lock to the file (= the file is not in progress of being written). FUSE Mediation Router will wait until the file lock is granted. Setting to false FUSE Mediation Router will poll the file even if its in progress of being written (= this is the behavior of FUSE Mediation Router 1.4). |
consumer.recursive | true/false | if a directory, will look for changes in files in all the sub directories. Notice: Default value in FUSE Mediation Router 1.4 or older is true. In FUSE Mediation Router 1.5 the default value is changed to false. |
consumer.regexPattern | null | will only fire a an exchange for a file that matches the regex pattern |
consumer.alwaysConsume | false | FUSE Mediation Router 1.5: @deprecated. Is used to force consuming the file even if it hasn't changed since last time it was consumed. Is useful if you for instance move files back into a folder and the file keeps the original timestamp. |
consumer.timestamp | true | FUSE Mediation Router 1.5: @deprecated. This
option is introduced to have similar name as the same option in FTP component. Setting this option will
internally in FUSE Mediation Router set the consumer.alwaysConsume option to the ! value .
So if this option is true, then alwaysConsume is false and vice verca. |
consumer.generateEmptyExchangeWhenIdle | false | @deprecated. Option only for the FileConsumer. If this option is true and there was no files to process we simulate processing a single empty file, so an exchange is fired. Note: In this situation the File attribute in FileExchange is null. |
lock | true | if true will lock the file for the duration of the processing |
delete | false | If delete is true then the file will be deleted when it is processed (the default is to move it, see below) |
noop | false | If true then the file is not moved or deleted in any way (see below). This option is good for read only data, or for ETL type requirements. |
moveNamePrefix | .camel/ | The prefix String perpended to the filename when moving it. For example to move processed files into the done directory, set this value to 'done/' |
moveNamePostfix | null | The postfix String appended to the filename when moving it. For example to rename processed files from foo to foo.old set this value to '.old' |
append | true | When writing do we append to the end of the file, or replace it? |
autoCreate | true | If set to true FUSE Mediation Router will create the directory to the file if the file path does not exists - Uses File#mkdirs() |
bufferSize | 128kb | Write buffer sized in bytes. FUSE Mediation Router uses a default of 128 * 1024 bytes. |
ignoreFileNameHeader | false | @deprecated. If this flag is enabled then producers will ignore the 'org.apache.camel.file.name' header and generate a new dynamic filename |
excludedNamePrefixes | null | @deprecated. Is used to exclude files if filename is starting with any of the given prefixes. The parameter is a String[] |
excludedNamePostfixes | null | @deprecated. Is used to exclude files if filename is ending with any of the given prefixes. The parameter is a String[] |
excludedNamePrefix | null | FUSE Mediation Router 1.5: Is used to exclude files if filename is starting with the given prefix. |
excludedNamePostfix | null | FUSE Mediation Router 1.5: Is used to exclude files if filename is ending with the given postfix. |
expression | null | FUSE Mediation Router 1.5: Use expression to dynamically set the filename. This
allows you to very easily set dynamic pattern style filenames. If an expression
is set it take precedes over the org.apache.camel.file.name
header. (Note: The header can itself also be an expression). The expression
options supports both String and Expression types. If the expression is a String
type then its always evaluated using the File Language. If the expression is an Expression type
then this type is of course used as it - this allows for instance to use OGNL as expression too. |
preMoveNamePrefix | null | FUSE Mediation Router 1.5.1/2.0: The prefix String perpended to the filename when moving it before processing. For example to move in progress files into the inprogress directory, set this value to 'inprogress/' |
preMoveNamePostfix | null | FUSE Mediation Router 1.5.1/2.0: The postfix String appended to the filename when moving it before processing. For example to rename in progress files from foo to foo.inprogress set this value to '.inprogress' |
preMoveExpression | null | FUSE Mediation Router 1.5.1/2.0: Use expression to dynamically set the filename when moving it before processing. For example to move in progress file into the order directory and use ,bak as extension set this value to 'order/$\{file:name.noext}.bat' |
By default the file is locked for the duration of the processing.
After the route has completed they are moved into the .camel subdirectory; so that they appear to be deleted.
The File Consumer will always skip any file which name starts with a dot, such
as ".", ".camel", ".m2" or ".groovy"
.
Only files (not directories) is matched for valid filename if options such as:
consumer.regexPattern, excludeNamePrefix,
excludeNamePostfix
is used. Notice: this only works properly in FUSE Mediation Router 1.5.0,
due to issue CAMEL-920.
In FUSE Mediation Router 1.5 the file consumer will avoid polling files that is currently in the progress of being written (see option consumer.exclusiveReadLock). However this requires FUSE Mediation Router being able to rename the file for its testing. If the FUSE Mediation Router user hasn't this rights on the file system, you can set this option to false to revert the change to the default behavior of FUSE Mediation Router 1.4 or older.
The recursive option has changed its default value from true to false in FUSE Mediation Router 1.5.0.
Any move or delete operations is executed after (post command) the routing has completed. So during processing of the Exchange the file is still located in the inbox folder. Lets illustrate this with an example:
from("file://inobox?m oveNamePrefix=done/").to("bean:handleOrder");
When a file is dropped in the inbox folder the file consumer notices this and creates
a new FileExchange
that is routed to the handleOrder bean. The bean
then processes the File. At this point in time the File is still located in the inbox
folder. After the bean completes and thus the route is completed the file consumer will
perform the move operation and move the file to the done sub folder.
By default FUSE Mediation Router will move consumed files to the sub folder
.camel
relative where the file was consumed.
Available in FUSE Mediation Router 1.5.1 or newer We have introduced a pre move operation to move files before they are processed. This allows you to mark which files has been scanned as they are moved to this sub folder before being processed. The following options support pre move:
preMoveNamePrefix
preMoveNamePostfix
preMoveExpression
from("file://inobox?preMoveNamePrefix=inprogress/").to("bean:handleOrder");
You can combine the pre move and the regular move:
from("file://inobox?preMoveNamePrefix=inprogress/&moveNamePrefix=../done/").to("bean:handleOrder");
So in this situation the file is in the inprogress folder when being processed, and after it's processed it's moved to the done folder.
The following message headers can be used to affect the behavior of the component
Header | Description |
---|---|
org.apache.camel.file.name | Specifies the output file name (relative to the endpoint directory) to be used for the output message when sending to the endpoint. If this is not present and no expression either then a generated message Id is used as filename instead. |
org.apache.camel.file.name.produced | New in FUSE Mediation Router 1.4: The actual absolute filepath (path + name) for the output file that was written. This header is set by FUSE Mediation Router and its purpose is providing end-users the name of the file that was written. |
When FUSE Mediation Router is producing files (writing files) there are a few gotchas how to set a filename of your choice. By default FUSE Mediation Router will use the message id as the filename, and since the message id is normally a unique generated id you will end up with filenames such as: ID-MACHINENAME\2443-1211718892437\1-0. Such a filename is not desired and therefore best practice is to provide the filename in the message header "org.apache.camel.file.name".
The sample code below produces files using the message id as the filename:
from("direct:report").to("file:target/reports");
To use report.txt as the filename you have to do:
from("direct:report").setHeader(FileComponent.HEADER_FILE_NAME, constant("report.txt")).to( "file:target/reports");
Canel will default try to auto create the folder if it does not exists, and this is a bad combination with the UUID filename from above. So if you have:
from("direct:report").to("file:target/reports/report.txt");
And you want FUSE Mediation Router to store in the file report.txt and autoCreate is true, then FUSE Mediation Router will create the folder: target/reports/report.txt/. To fix this set the autoCreate=false and create the folder target/reports manually.
from("direct:report").to("file:target/reports/report.txt?autoCreate=false");
With auto create disabled FUSE Mediation Router will store the report in the report.txt as expected.
This only applies to FUSE Mediation Router 1.x The file consumer scans for new files by keeping an internal modified timestamp of the last consumed file. So if you copy a new file that has an older modified timestamp, then FUSE Mediation Router will not pickup this file. This can happen if you are testing and you copy the same file back to the folder that has just been consumed. To remedy this modify the timestamp before copying the file back.
In FUSE Mediation Router 1.5 we have support for setting the filename using an
expression. This can be set either using the expression
option or as a string based File Language expression in the
org.apache.camel.file.name
header. See the File Language for some samples.
from("file://inputdir/?delete=true").to("file://outputdir")
Listen on a directory and create a message for each file dropped there. Copy the contents to the outputdir and delete the file in the inputdir.
from("file://inputdir/").process(new Processor() { public void process(Exchange exchange) throws Exception { Object body = exchange.getIn().getBody(); // do some business logic with the input body } });
Body will be File object pointing to the file that was just dropped to the inputdir directory.
from("file://inputdir/").convertBodyTo(String.class).to("jms:test.queue")
By default the file endpoint sends a FileMessage which contains a File as body. If you send this directly to the jms component the jms message will only contain the File object but not the content. By converting the File to a String the message will contain the file contents what is probably what you want to do.
The route above using Spring DSL:
<route> <from uri="file://inputdir/"/> <convertBodyTo type="java.lang.String"/> <to uri="jms:test.queue"/> </route>
FUSE Mediation Router is of course also able to write files, eg. producing files. In the sample below we receive some reports on the SEDA queue that we processes before they are written to a directory.
public void testToFile() throws Exception { MockEndpoint mock = getMockEndpoint("mock:result"); mock.expectedMessageCount(1); mock.expectedFileExists("target/test-reports/report.txt"); template.sendBody("seda:reports", "This is a great report"); assertMockEndpointsSatisfied(); } protected JndiRegistry createRegistry() throws Exception { // bind our processor in the registry with the given id JndiRegistry reg = super.createRegistry(); reg.bind("processReport", new ProcessReport()); return reg; } protected RouteBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { public void configure() throws Exception { // the reports from the seda queue is processed by our processor // before they are written to files in the target/reports directory from("seda:reports").processRef("processReport").to("file://target/test-reports", "mock:result"); } }; } private class ProcessReport implements Processor { public void process(Exchange exchange) throws Exception { String body = exchange.getIn().getBody(String.class); // do some business logic here // set the output to the file exchange.getOut().setBody(body); // set the output filename using java code logic, notice that this is done by setting // a special header property of the out exchange exchange.getOut().setHeader(Exchange.FILE_NAME, "report.txt"); } }
In this sample we want to move consumed files to a backup folder using todays date as a sub foldername:
from("file://inbox?expression=backup/${date:now:yyyyMMdd}/${file:name}").to("...");
See File Language for more samples.
Using a single route, it is possible to write a file to any number of subdirectories. If you have a route setup as such
<route> <from uri="bean:myBean"/> <to uri="file:/rootDirectory"/> </route>
You can have myBean set the FileComponent.HEADER_FILE_NAME to values such as:
FileComponent.HEADER_FILE_NAME = hello.txt => /rootDirectory/hello.txt FileComponent.HEADER_FILE_NAME = foo/bye.txt => /rootDirectory/foo/bye.txt
This allows you to have a single route to write files to multiple destinations.
File Language