Camel File コンポーネント

Apache Camel Advent Calendar 8日目の記事は、サポート担当古市が担当します。テーマは、「Camel File コンポーネント」

Apache Camel 1.0 から提供されている古参のコンポーネントであり、クラウドや AIなどで賑わっている昨今においても、サポート業務で度々お問い合わせを受ける人気コンポーネントの1つです。 こんな作業を検討されている方は、ぜひ camel-file コンポーネントのご利用をご検討ください。

  • 特定ディレクトリーからファイルを定期的に読み込む
  • 特定ディレクトリーへファイルを出力する

よく聞く話では、

  • メインフレームとの連携にファイルを使用
  • 工作機器やガジェットとの連携にファイルを使用
  • ファイルデータ転送

といった用途で使用されているようです。 camel ftp コンポーネントもありますので、FTP環境をお持ちの方は、こちらを検討しても良いかもしれません。 また、ファイルデータ転送については、本当に必要なデータのみを必要なタイミングで転送しているか再考してみると気付きがあるはずです。camel route はあらゆるプロトコルと連動し柔軟にインテグレーションを実装できますので、「夜間バッチで特定ディレクトリ配下のファイルを全て別環境へコピーする」といった運用では勿体無く感じます。(もちろん、メリットもありますので否定はしません。)

  • camel を使えばシンプルな運用ができそうだけれど、どう実装すれば良いかわからない。
  • camel ルートを作ってみたけれど、もっと良い方法があるか気になる。

こういった方は、ぜひ Red Hat セールスチームへご相談いただければと思います。コンサルティングサービスやトレーニングサービスのご提案が可能です。もちろん、Apache Camel コミュニティーが運用する SNS で相談も可能です。

camel.apache.org

それでは、簡単なデモで試してみます。 camel-file に関するブログ記事などが散見されますが、ご利用するにあたり、製品ドキュメントもしくはコミュニティードキュメントを確認していただく方法を強くお勧めします。 ここでは、コミュニティードキュメントを見ていきます。

camel.apache.org

圧倒的な query parameter の量に驚かれるかもしれません。この豊富なオプションが、camel を使う理由の1つでしょう。 "Usage"セクションには、多数サンプルが記述されています。きっとイメージしている使用例が見つかるはずですので、一通り見ていただくと良いです。

よくあるケースとして、CSVファイルを読み込んでみます。まずは、ファイル内容を出力してみます。

% tree
.
├── data
│   └── sample.csv
└── Hello.java

2 directories, 2 files
% cat data/sample.csv 
1,Bob,23
2,Nancy,30
3,David,18
% cat Hello.java 
import org.apache.camel.builder.RouteBuilder;

public class Hello extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        from("file:data?charset=utf-8")
            .log("${body}")
            .log("${headers}");
    }
}
% 
% camel run Hello.java 

~割愛~

2025-08-20 10:11:59.245  INFO 6442 --- [           main] e.camel.impl.engine.AbstractCamelContext : Apache Camel 4.13.0 (Hello) started in 93ms (build:0ms init:0ms start:93ms boot:2s138ms)
2025-08-20 10:12:00.217  INFO 6442 --- [5 - file://data] Hello.java:8                             : 1,Bob,23
2,Nancy,30
3,David,18
2025-08-20 10:12:00.220  INFO 6442 --- [5 - file://data] Hello.java:9                             : {CamelFileAbsolute=false, CamelFileAbsolutePath=/Users/hfuruich/training/camel/data/sample.csv, CamelFileInitialOffset=org.apache.camel.support.resume.Resumables$AnonymousResumable@7102b6dc, CamelFileLastModified=1755651928676, CamelFileLength=30, CamelFileName=sample.csv, CamelFileNameConsumed=sample.csv, CamelFileNameOnly=sample.csv, CamelFileParent=data, CamelFilePath=data/sample.csv, CamelFileRelativePath=sample.csv, CamelMessageTimestamp=1755651928676}

camel-file consumer endpoint が実行された時点で exchange.body には Fileのラップオブジェクトがセットされますが、.log("{$body}") 実行時に自動的にファイルを読み込み文字列をターミナルへ出力しています。 大量のヘッダー値も出力されています。個々のヘッダー値についてはコミュニティードキュメントの "MESSAGE HEADERS"セクションに解説がありますので、そちらをご覧ください。

data ディレクトリーには .camel ディレクトリーが作成され、sample.csv ファイルはそちらへ移動しています。

挙動確認のために .log("${headers}") をわざわざ記載せず、前回ご紹介した trace を使ってモニターしても良いです。 その場合、"initialDelay" オプションをセットし、consumer endpoint のポーリングが開始される前に trace を開始します。

% cat Hello.java 
import org.apache.camel.builder.RouteBuilder;

public class Hello extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        from("file:data?charset=utf-8&initialDelay=30000")
            .log("${body}");
    }
}
% 
% camel run Hello.java --background
Running integration with the following configuration:
    --camel-version=4.13.0
Running Camel Main: Hello in background with PID: 8717 (waiting to startup)
Camel Main: Hello (state: Running)
% camel trace
 PID   NAME   AGE  STATUS   TOTAL  QUEUE  FILTER  PATTERN 
 8717  Hello   6s  Standby      0      0                  
% camel trace Hello --action=start
%
% ls data
sample.csv
% ls data
%
% camel trace Hello --action=dump
2025-08-20 10:29:51.711   8717 --- [) thread #5 - file://data]                              route1/*--> :     1 - Created
  Endpoint    file://data?charset=utf-8&initialDelay=30000 
  Exchange    (DefaultExchange)  InOnly  FD18A47B92D4549-0000000000000000 
  Message     (GenericFileMessage) 
  Header      (Boolean)                                     CamelFileAbsolute  false                                                                  
  Header      (String)                                  CamelFileAbsolutePath  /Users/hfuruich/training/camel/data/sample.csv                         
  Header      (resume.Resumables.AnonymousResumable)   CamelFileInitialOffset  org.apache.camel.support.resume.Resumables$AnonymousResumable@43068e59 
  Header      (Long)                                    CamelFileLastModified  1755651928676                                                          
  Header      (Long)                                          CamelFileLength  30                                                                     
  Header      (String)                                          CamelFileName  sample.csv                                                             
  Header      (String)                                  CamelFileNameConsumed  sample.csv                                                             
  Header      (String)                                      CamelFileNameOnly  sample.csv                                                             
  Header      (String)                                        CamelFileParent  data                                                                   
  Header      (String)                                          CamelFilePath  data/sample.csv                                                        
  Header      (String)                                  CamelFileRelativePath  sample.csv                                                             
  Header      (Long)                                    CamelMessageTimestamp  1755651928676 (2025-08-20 10:05:28 / 24m47s ago)             
  Body        (org.apache.camel.component.file.GenericFile) (size: 30 bytes: 32) 
  1,Bob,23\n2,Nancy,30\n3,David,18 
2025-08-20 10:29:51.718   8717 --- [) thread #5 - file://data]                              route1/log1 :     2 - Processed (1ms)
  Exchange    (DefaultExchange)  InOnly  FD18A47B92D4549-0000000000000000 
  Message     (GenericFileMessage) 
  Header      (Boolean)                                     CamelFileAbsolute  false                                                                  
  Header      (String)                                  CamelFileAbsolutePath  /Users/hfuruich/training/camel/data/sample.csv                         
  Header      (resume.Resumables.AnonymousResumable)   CamelFileInitialOffset  org.apache.camel.support.resume.Resumables$AnonymousResumable@43068e59 
  Header      (Long)                                    CamelFileLastModified  1755651928676                                                          
  Header      (Long)                                          CamelFileLength  30                                                                     
  Header      (String)                                          CamelFileName  sample.csv                                                             
  Header      (String)                                  CamelFileNameConsumed  sample.csv                                                             
  Header      (String)                                      CamelFileNameOnly  sample.csv                                                             
  Header      (String)                                        CamelFileParent  data                                                                   
  Header      (String)                                          CamelFilePath  data/sample.csv                                                        
  Header      (String)                                  CamelFileRelativePath  sample.csv                                                             
  Header      (Long)                                    CamelMessageTimestamp  1755651928676 (2025-08-20 10:05:28 / 24m47s ago)             
  Body        (org.apache.camel.component.file.GenericFile) (size: 30 bytes: 32) 
  1,Bob,23\n2,Nancy,30\n3,David,18 
2025-08-20 10:29:51.711   8717 --- [) thread #5 - file://data]                              route1/*<-- :     3 - Completed (success) (1ms)
  Endpoint    file://data?charset=utf-8&initialDelay=30000 
  Exchange    (DefaultExchange)  InOnly  FD18A47B92D4549-0000000000000000 
  Message     (GenericFileMessage) 
  Header      (Boolean)                                     CamelFileAbsolute  false                                                                  
  Header      (String)                                  CamelFileAbsolutePath  /Users/hfuruich/training/camel/data/sample.csv                         
  Header      (resume.Resumables.AnonymousResumable)   CamelFileInitialOffset  org.apache.camel.support.resume.Resumables$AnonymousResumable@43068e59 
  Header      (Long)                                    CamelFileLastModified  1755651928676                                                          
  Header      (Long)                                          CamelFileLength  30                                                                     
  Header      (String)                                          CamelFileName  sample.csv                                                             
  Header      (String)                                  CamelFileNameConsumed  sample.csv                                                             
  Header      (String)                                      CamelFileNameOnly  sample.csv                                                             
  Header      (String)                                        CamelFileParent  data                                                                   
  Header      (String)                                          CamelFilePath  data/sample.csv                                                        
  Header      (String)                                  CamelFileRelativePath  sample.csv                                                             
  Header      (Long)                                    CamelMessageTimestamp  1755651928676 (2025-08-20 10:05:28 / 24m47s ago)             
  Body        (org.apache.camel.component.file.GenericFile) (size: 30 bytes: 32) 
  1,Bob,23\n2,Nancy,30\n3,David,18 

traceログからも、各Header値を確認できました。body には org.apache.camel.component.file.GenericFileオブジェクトがセットされていることも読み解けます。 ある程度動作確認をしたあとは、traceデータの消去や実行中のインテグレーションの停止もお忘れなく。

% camel trace Hello --action=stop
% camel trace Hello --action=clear
% camel stop Hello
Shutting down Camel integration (PID: 8717)
%

camel-jbang で簡単に動作確認をできるので、コミュニティードキュメントを参考にしつつ、まずは気になるオプションを試してみてください。

読み込んだ csvファイルを分割してデータ変換することもできます。

hfuruich@hfuruich-mac camel % cat Hello.java 
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.model.dataformat.JsonLibrary;

public class Hello extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        from("file:data?charset=utf-8")
         .split(body().tokenize("\n"))
            .unmarshal().csv()
            .marshal().json(JsonLibrary.Jackson)
            .log("${body}");
    }
}
% camel run Hello.java 

~割愛~

2025-08-20 10:59:24.418  INFO 12558 --- [           main] e.camel.impl.engine.AbstractCamelContext : Apache Camel 4.13.0 (Hello) started in 99ms (build:0ms init:0ms start:99ms boot:1s960ms)
2025-08-20 10:59:25.403  INFO 12558 --- [5 - file://data] Hello.java:12                            : [["1","Bob","23"]]
2025-08-20 10:59:25.404  INFO 12558 --- [5 - file://data] Hello.java:12                            : [["2","Nancy","30"]]
2025-08-20 10:59:25.404  INFO 12558 --- [5 - file://data] Hello.java:12                            : [["3","David","18"]]

条件式も camel は提供しているので、アイディア次第で柔軟なルーティングか可能です。 スモールスタートでまずはファイルの入出力を試していただき、そこから少しずつルーティングの規模を広げてアイディアを形にしていってください。

明日の advent calendar 9日目では、「Camel kafka コンポーネント」についてご紹介します。 アドベントカレンダーの一覧はこちらです。 qiita.com

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。