将csv文件按字段数(每行不同)拆分到不同的目标端点

时间:2014-08-25 14:19:48

标签: apache-camel

我创建了一个读取csv文件的处理器,该文件包含具有不同字段数的行。生产者的构造函数获取一个整数列表,告诉它哪些行是感兴趣的(例如,包含13或65个字段的行)。

对于每个字段计数,输出应该是一个字节[] - 所以我将有一个字节[],其中所有行包含13个字段,另一个包含所有包含65个字段的行。

我以为我可以为每个块创建一个新的交换,并设置一个标题值“fieldCount”。此处理器的输出将进入choice()。when(header ...)route - 将每个块路由到不同的端点集。

但如何创建新的交流?我阅读了this并以这种方式获得了制作人模板ProducerTemplate producer = exchange.getContext().createProducerTemplate();,但我总是得到defaultEndpoint must be specified。但我的处理器不是也不应该知道任何端点。什么是“违约点”?如何正确设置?

我也研究过split() - 模式,但这似乎对我的情况没什么帮助。有了它我可以改变我的处理器发出List>并且只是拆分但是选择/当部分更复杂时,或者我需要第二个处理器来创建一个带有每个Map的标头集的byte []。

那么这里最好的方法是什么?

2 个答案:

答案 0 :(得分:2)

我认为最简单的方法是:

public class MyRouteBuilder extends RouteBuilder {  

   @Override
   public void configure() throws Exception {
     from("file://file.csv") 
       .split(body(String.class).tokenize("\n"))     
       .processor(new FieldCountHeaderProcessor())  
       .aggregate(header("fieldCount"))
       .processor(new ByteArrayConverterProcessor()) 
       .choice()
       .when(header("fieldCount").isEqualTo("13")).to("direct:ENDPOINT_FOR_13_FIELDS")   
       .when(header("fieldCount").isEqualTo("65")).to("direct:ENDPOINT_FOR_65_FIELDS")     
       .endChoice();
   }
}

您只需要实施FieldCountHeaderProcessorByteArrayConverterProcessor

您还可以实施ByteArrayAggregationStrategy(请参阅AggragationStrategy),该byte[]会直接汇总到ByteArrayConverterProcessor,从而无需使用public class MyRouteBuilderWithAggregationStrategy extends RouteBuilder { @Override public void configure() throws Exception { from("file://file.csv") .split(body(String.class).tokenize("\n")) .processor(new FieldCountHeaderProcessor()) .aggregate(header("fieldCount"), new ByteArrayAggregationStrategy()) .choice() .when(header("fieldCount").isEqualTo("13")).to("direct:ENDPOINT_FOR_13_FIELDS") .when(header("fieldCount").isEqualTo("65")).to("direct:ENDPOINT_FOR_65_FIELDS") .endChoice(); } } 。例如:

{{1}}

答案 1 :(得分:0)

同时我创建了另一个同样有效的解决方案:

@Override
public void configure() throws Exception {
    from(DIRECT_IN).process(new MyProcessor(Lists.newArrayList(FIELD_COUNT_1, FIELD_COUNT_2))).split().body().choice()
                   .when(new CheckFieldCount(FIELD_COUNT_1))
                   .to(MOCK_FIELD_COUNT1)
                   .when(new CheckFieldCount(FIELD_COUNT_2))
                   .to(MOCK_FIELD_COUNT2)
                   .otherwise()
                   .to(MOCK_NOT_RELEVANT);
}

" MyProcessor"处理具有不同字段计数的csv-byte []到List。 " CsvBlock"是一个包含fieldCount(int)和data(byte [])的原始类。 " CheckFieldCount"实现谓词它只是在交换数据中检查给定的int。 在这种情况下,CsvBlock被发送到mock。对于我的真实代码,我需要另一个处理器从CsvBlock中提取数据(原始代码,但另一个类)。 乍一看,我认为里卡多的方式更好,但这对我来说意味着更多的工作。