Apache Camel 2.17.3 - 使用 bindy 解组 CSV 流时出现异常

问题描述 投票:0回答:2

我编写了一个简单的路线来读取 CSV 文件并将其保存在 JSON 格式的新文件中。

当我尝试拆分和流式传输正文时,解组会因“.IllegalArgumentException:CSV 中没有定义记录”而中断。

但是,无需拆分和流式传输,它也能正常工作!

Unmarshal 使用 BindyCsvDataFormat 和 CustomCsvRecord 定义字段。

CSV Sample:
HEADER_1;HEADER_2;HEADER_3;HEADER_4;HEADER_5
data11;data12;data13;data14;data15
data21;data22;data23;data24;data25

您能帮助我了解这是正确的行为吗?如果是,我如何控制读取大文件?

请参考以下:

public class MyRouteBuilder extends RouteBuilder {

    public void configure() {

        BindyCsvDataFormat bindy = new BindyCsvDataFormat(com.demo.camel.CustomCsvRecord.class);
        from("file://data?move=../completed/&include=.*.csv&charset=UTF-8")
            .log("Reading file..")
            // .split(body().tokenize("\n")).streaming()
            // .throttle(2)
            // .timePeriodMillis(3000)
            .unmarshal(bindy)
            .marshal().json(true)
            .log("writing to file")
            .to("file://target/messages?fileExist=Append");
        }
    }

    @CsvRecord(separator = ";", skipFirstLine = true )
    public class CustomCsvRecord implements Serializable{

    private static final long serialVersionUID = -1537445879742479656L;

    @DataField(pos = 1)
    private String header_1;

    @DataField(pos = 2)
    private String header_2;

    @DataField(pos = 3)
    private String header_3;

    @DataField(pos = 4)
    private String header_4;

    @DataField(pos = 5)
    private String header_5;
        public String getHeader_1() {
        return header_1;
    }

    public void setHeader_1(String header_1) {
        this.header_1 = header_1;
    }

    public String getHeader_2() {
        return header_2;
    }

    public void setHeader_2(String header_2) {
        this.header_2 = header_2;
    }

    public String getHeader_3() {
        return header_3;
    }

    public void setHeader_3(String header_3) {
        this.header_3 = header_3;
    }

    public String getHeader_4() {
        return header_4;
    }

    public void setHeader_4(String header_4) {
        this.header_4 = header_4;
    }

    public String getHeader_5() {
        return header_5;
    }

    public void setHeader_5(String header_5) {
        this.header_5 = header_5;
    }   
}
apache-camel integration
2个回答
3
投票

难道你设置了skipFirstLine = true?但由于您使用换行符进行分割,因此跳过第一行意味着没有行可以解析 CSV。试试这个吧

.split().tokenize("\n", 1000).streaming()
。这基本上意味着我们要根据代币进行拆分” “并且我们想要将 N 行组合在一起。在本例中,它是 1000,因此最多会将 1000 行组合在一起。

因此,如果您发送 10 000 行,它会将它们分成 10 个块。

现在的问题是,如果您设置了skipFirstLine,它将跳过第一行。由于您之前分割了每一行,因此当涉及 CSV 解析器时,它会跳过该行,因为这是它被告知要执行的操作。因此,没有什么可解析的,它抱怨没有记录。

现在的问题是,每 1000 行进行一次分割后会发生什么,得到 10000 行。它会删除每个分割块中的第一行吗?我怀疑是这样。我认为最好的办法是在拆分之前添加一个处理器。将正文转换为 byte[]。搜索第一个“ " 并简单地删除该行或获取该索引之后的 byteArray。然后您可以进行正常拆分并删除skipFirstRow。

此外,您的输出位于列表中,但这是由于您的映射所致。


0
投票

如果您想跳过 CSV 的第一行,这只是一个快速提示,可以让事情变得更容易。 .tokenize() 方法中有一个方便的功能,您可以使用一个简单的标志告诉 Camel 忽略第一行。看起来像这样:

.split().tokenize("\n", 1000, true).streaming()

通过将最后一个参数设置为 true,Camel 巧妙地跳过第一个换行符,使标题不被分割。这意味着您的

skipFirstLine = true
中不再需要
@CsvRecord
,因此请继续将其设置为 false 或将其删除。这样,当您将文件分成一千行的块时,它不会跳过每个块的第一行 - 只会跳过文件开头的标题。

这里是 Camel's(4.4.x) 的文档 tokenize-language

© www.soinside.com 2019 - 2024. All rights reserved.