Статьи

Изучение Apache Camel Core – Файловый компонент

File Poller — очень полезный механизм для решения типичных проблем в сфере ИТ. Встроенный file компонент Camel  чрезвычайно гибок, и для настройки доступно множество вариантов. Давайте рассмотрим несколько общих способов использования.

Опрос каталога для входных файлов

Вот типичный верблюд,  Route используемый каждую секунду для опроса каталога для входных файлов.

import org.slf4j.*;
import org.apache.camel.*;
import org.apache.camel.builder.*;
import java.io.*;

public class FileRouteBuilder extends RouteBuilder {
    static Logger LOG = LoggerFactory.getLogger(FileRouteBuilder.class);
    public void configure() {
        from("file://target/input?delay=1000")
        .process(new Processor() {
            public void process(Exchange msg) {
                File file = msg.getIn().getBody(File.class);
                LOG.info("Processing file: " + file);
            }
        });
    }
}

Запустите это следующим образом:

mvn compile exec:java -Dexec.mainClass=org.apache.camel.main.Main -Dexec.args='-r camelcoredemo.FileRouteBuilder'

Программа начнет опрашивать вашу  target/input папку в вашей текущей директории и будет ждать поступления файлов. Чтобы протестировать с входными файлами, вам нужно открыть другой терминал, а затем создать несколько файлов, например:

echo 'Hello 1' > target/input/test1.txt
echo 'Hello 2' > target/input/test2.txt

Теперь вы должны увидеть, как первое окно подсказки начинает собирать файлы и передавать их на следующий  Processor шаг. В  Processor, мы получаем  File объект из тела сообщения. Затем он просто записывает свое имя файла. Вы можете ударить,  CTRL+C когда вы закончите.

Там много настраиваемых опций из file компонента. Вы можете использовать это в URL, но большинство настроек по умолчанию достаточно, чтобы начать работу, как показывает простой пример, приведенный выше. Некоторые из этих поведений по умолчанию таковы, что если папка ввода не существует, она создаст ее. И когда файл Routeзавершится обработкой  , он будет перемещен в  .camelпапку. Если вам вообще не нужен файл после обработки, укажите его в  delete=true URL.

Чтение содержимого файла и преобразование в разные типы

По умолчанию  file компонент создает  org.apache.camel.component.file.GenericFile объект для каждого найденного файла и передает его  Route как тело сообщения. Вы можете получить всю информацию о вашем файле через этот объект. В качестве альтернативы вы также можете использовать  Exchange API для автоматического преобразования объекта тела сообщения в тип, который вы ожидаете получить (например, как в случае с  msg.getIn().getBody(File.class)). В приведенном выше примере  File это тип, который вы ожидаете получить из тела сообщения, и Camel попытается преобразовать его для вас. Camel использует пространство реестра контекста, чтобы предварительно зарегистрировать многие из них  TypeConverter, которые могут обрабатывать преобразование большинства распространенных типов данных (например, примитивов Java). Эти  TypeConverters  являются мощным средством , чтобы сделать ваш  Route и  Processor более гибким и портативным.

Camel не только преобразует только ваш  File объект из тела сообщения, но также может читать содержимое файла. Если ваши файлы основаны на символьном тексте, то вы можете просто сделать это.

       from("file://target/input?charset=UTF-8")
        .process(new Processor() {
            public void process(Exchange msg) {
                String text = msg.getIn().getBody(String.class);
                LOG.info("Processing text: " + text);
            }
        });

Это оно! Просто укажите, что это String тип, и Camel прочитает ваш файл и передаст текстовое содержимое всего файла в виде основного сообщения. Вы даже можете использовать  charset для изменения кодировки.

Если вы имеете дело с двоичным файлом, просто попробуйте  byte[] bytes =msg.getIn().getBody(byte[].class); преобразование. Довольно круто, да?

Опрос и обработка больших файлов

При работе с большими файлами в file компоненте есть несколько опций, которые вы, возможно, захотите использовать для обеспечения правильной обработки. Например, вы можете переместить входной файл в  staging папку до  Route начала обработки; и когда это будет сделано, переместите его в  .completed папку.

       from("file://target/input?preMove=staging&move=.completed")
        .process(new Processor() {
            public void process(Exchange msg) {
                File file = msg.getIn().getBody(File.class);
                LOG.info("Processing file: " + file);
            }
        });

Для правильной подачи входных файлов в папку опроса лучше всего, если отправитель сначала генерирует входные файлы во временной папке, и только когда он будет готов, затем переместите его в папку опроса. Это сведет к минимуму чтение неполного файла,  Route если для создания входного файла может потребоваться время. Другое решение этой проблемы — настроить fileконечную точку для чтения папки опроса только при наличии сигнала или при наличии файла маркера готовности. Например:

        from("file://target/input?preMove=staging&move=.completed&doneFileName=ReadyFile.txt")
        .process(new Processor() {
            public void process(Exchange msg) {
                File file = msg.getIn().getBody(File.class);
                LOG.info("Processing file: " + file);
            }
        });

Код выше будет читать  папку только тогда, когда   файл существует. Файл маркера может быть просто пустым файлом, и он будет удален Camel после опроса. Это решение позволит отправителю генерировать входные файлы независимо от того, сколько времени это займет. target/inputReadyFile.txt

Еще одна проблема, связанная с обработкой больших файлов, заключается в том, чтобы избежать загрузки всего содержимого файла в память для обработки. Чтобы быть более практичным, вы хотите разбить файл на записи (например, на строку) и обработать его одну за другой (это называется «потоковая передача»). Вот как вы это сделаете, используя Camel.

 from("file://target/input?preMove=staging&move=.completed")
        .split(body().tokenize("\n"))
        .streaming()
        .process(new Processor() {
            public void process(Exchange msg) {
                String line = msg.getIn().getBody(String.class);
                LOG.info("Processing line: " + line);
            }
        });

Это  Route позволит вам обрабатывать файлы большого размера, не занимая слишком много памяти, и очень эффективно обрабатывает их построчно.

Написание сообщений обратно в файл

file Компонент также может быть использован для записи сообщений в файлы. Напомним, что мы можем использовать  datasetкомпоненты для создания образцов сообщений. Мы будем использовать это для подачи  Route и отправки  file компонента, чтобы вы могли видеть, что каждое сгенерированное сообщение будет сохранено в файл.

package camelcoredemo;

import org.slf4j.*;
import org.apache.camel.*;
import org.apache.camel.builder.*;
import org.apache.camel.main.Main;
import org.apache.camel.component.dataset.*;

public class FileDemoCamel extends Main {
    static Logger LOG = LoggerFactory.getLogger(FileDemoCamel.class);
    public static void main(String[] args) throws Exception {
        FileDemoCamel main = new FileDemoCamel();
        main.enableHangupSupport();
        main.addRouteBuilder(createRouteBuilder());
        main.bind("sampleGenerator", createDataSet());
        main.run(args);
    }
    static RouteBuilder createRouteBuilder() {
        return new RouteBuilder() {
            public void configure() {
                from("dataset://sampleGenerator")
                .to("file://target/output");
            }
        };
    }
    static DataSet createDataSet() {
        return new SimpleDataSet();
    }
}

Скомпилируйте и запустите его.

mvn compile exec:java -Dexec.mainClass=camelcoredemo.FileDemoCamel

По завершении вы увидите, что в папке будет сгенерировано 10 файлов target/output с именем в  ID-<hostname>-<unique-number>-<msg-seq-num> формате.

В  компоненте « Файл» доступны дополнительные параметры,  которые вы можете изучить. Попробуйте это с маршрутом  и убедитесь сами.