【Apache Camel】Fileコンポーネントを使う


Fileコンポーネントとは

Fileコンポーネントはファイルシステムへのアクセスするためのコンポーネントで、ファイルやディレクトリの入出力が可能です。

Consumer/Producer

FileコンポーネントはConsumer/Producerの両方の役割を担います。
Consumerとしては、ファイル・ディレクトリの読み込みや読み込んだファイルの移動・削除ができます。Producerとしては、ファイルへの書き込み等を行うことができます。

Consumer/Producerでは、例として以下のようなことを実現することができます。

Consumer
- 指定したディレクトリに存在するファイルを読み込む
- 指定したファイルパスのファイルを読み込む
- 指定したファイルパスのファイルを削除する
- 条件に一致したファイルを読み込む

Producer
- 指定したパスにファイルを作成する
- 指定したパスにファイルを作成し、作成完了時に[ファイル名].doneのファイルを作成する

コンポーネントのURI

Fileコンポーネントを使用するためのURIは以下のようになります。

file:directoryName

コンテキストパス(directoryName)には処理対象のディレクトリを指定します。
指定されたdirectoryNameに存在するファイルに対して、Fileコンポーネントはアクセスして処理を行います。
このコンテキストパスに対して、オプションを指定することで様々な処理を行うことができます。
Fileコンポーネントのオプションは多くあり、各オプションの説明は以下の公式サイトに記載されています。

本記事でも、実装例を示しながらいくつかのオプションを説明したいと思います。

実装例

本節では、Java DSLで記載されたルートを用いて、Fileコンポーネントの実装例を示していきます。
あくまでも頻繁に使用されるオプションに絞って記載しており、記載したオプションも概要のみになりますので、詳細は前述の公式サイトのFileコンポーネントの説明を参照してください。

例)指定したディレクトリ中のファイルをコピーする

指定したディレクトリのファイルをコピーするルートです。
data/inputディレクトリ中の全てのファイルをdata/outputにコピーします。
noop=trueオプションを指定することで、リードオンリーになり、data/inputディレクトリ中のファイルは移動も削除もされません。
また、noop=trueオプションを指定することで自動的にidempotent=trueオプションも有効になり、同じファイルは処理されないようになります。

from("file:data/input?noop=true").to("file:data/output");

例)指定したディレクトリ中のファイルを移動する

指定したディレクトリのファイルを移動するルートです。
data/inputディレクトリ中の全てのファイルをdata/outputに移動します。
delete=trueにより、処理後にファイルが削除されます。

from("file:data/input?delete=true").to("file:data/output");

例)指定したディレクトリ中のファイルを再帰的に移動する

指定したディレクトリのファイルを、サブディレクトリに存在するファイルも含めて再帰的に移動するルートです。
サブディレクトリ自体は移動されません。
recursive=trueにより再帰的に処理することを指定しています。

from("file:data/input?delete=true&recursive=true").to("file:data/output");

例)処理完了後に.doneというファイルを作成する。

指定したディレクトリのファイルをコピーし、処理完了後に[ファイル名].doneというファイルを作成するルートです。
/data/outputディレクトリへ全てのファイルをコピー完了すると、コピー先のディレクトリに[ファイル名].doneファイルが生成されます。
${file:name}は処理中のファイル名を表します。

from("file:data/input?noop=true").to("file:data/output?doneFileName=${file:name}.done");

例)[ファイル名].doneというファイルを存在すれば、ファイルを移動する。

先ほどとは逆に、[ファイル名].doneというファイルを存在すれば、ファイルを移動します。

from("file:data/output?noop=true&doneFileName=${file:name}.done").to("file:data/output.done");

例)ファイル名のリストとテキストファイルの内容を取得する。

data/inputディレクトリ中のファイルを読み込み、ファイル名のリストとテキストファイルの内容を取得し出力します。
processメソッドでFileListProcessorプロセッサを指定しています。

from("file:data/input?noop=true").process(new FileListProcessor());

FileListProcessorプロセッサは以下の内容になっています。

FileListProcessor.java
package example.camelbegginer.file;

import java.util.Map;

import org.apache.camel.Exchange;
import org.apache.camel.Processor;

public class FileListProcessor implements Processor {

    @Override
    public void process(Exchange exchange) throws Exception {
        String body = exchange.getIn().getBody(String.class);
        System.out.println("body: " + body);

        Map<String, Object> headers = exchange.getIn().getHeaders();
        System.out.println("fileName: " + headers.get("CamelFileAbsolutePath"));

    }
}

processメソッドでは、以下のコードでファイルの内容を標準出力に出力しています。

        String body = exchange.getIn().getBody(String.class);
        System.out.println("body: " + body);

ファイル名などのファイルの情報はメッセージのヘッダに入ります。
以下のようにメッセージのヘッダを取得し、"CamelFileAbsolutePath"でファイルパスを取得し、標準出力に出力しています。

        Map<String, Object> headers = exchange.getIn().getHeaders();
        System.out.println("fileName: " + headers.get("CamelFileAbsolutePath"));

メッセージのヘッダーに入る値は以下のページを参照してください。
https://github.com/apache/camel/blob/master/components/camel-file/src/main/docs/file-component.adoc#message-headers

ファイルパス以外にも、ファイルサイズ、最終更新日等の情報を取得することができます。

例)指定した文字列をファイル名に含むファイルのみを処理する

指定した文字列をファイル名に含むファイルのみを処理するルートです。
filterFileオプションを使用し以下のように記述します。

from("file:data/input?noop=true&filterFile=$simple{file:name} contains 'file1'")
                        .to("file:data/output");

filterFile=$simple{file:name} contains 'file1'

上のfilterFileオプションの値は、ファイル名に"file1"という文字列を含む場合を表しています。
このfilterFileオプションの値は「Simple Expression Language」(Simple式言語)とFile Languageを用いて指定します。

Simple式言語はApache Camelの独自の式言語で、計算や値の参照の結果を出力するために使用され、$simple{変数}という書き方をします。
Simple式言語で、ほとんどの計算や値の参照を実現することができます。
また、File LanguageはSimple式言語の拡張で、ファイル関連の値の参照ができます。

先ほどの例での「file:name」はFile Languageでのファイル名の参照を表し、「$simple{file:name} contains 'file1'」全体はSimple式言語で、ファイル名に"file1"という文字列を含む場合を表すことになります。

Simple式言語とFile Languageの詳細は以下の公式サイトを参照してください。

例)指定したファイルをzipに圧縮する

Fileコンポーネントとは少し外れてしまいますが、Apache Camelの便利さを分かっていただくため、zipコンポーネントと組み合わせたファイル圧縮について説明します。
file1.txtというファイルをzip圧縮する場合は、以下のルートだけで簡単に実現することができます。

                    from("file:data/input?noop=true&fileName=file1.txt")
                        .marshal().zipFile()
                        .to("file:data/output");

なお、上述の「zipFile()」を利用するためには、以下の依存関係を追加しておく必要があります。

pom.xml
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-zipfile</artifactId>
            <version>${camel.version}</version>
        </dependency>

参考