【问题标题】:Apache Camel 2.17.3 - Exception unmarshalling CSV stream with bindyApache Camel 2.17.3 - 使用 bindy 解组 CSV 流的异常
【发布时间】:2017-01-23 00:28:19
【问题描述】:

我编写了一个简单的路径来读取 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;
    }   
}

【问题讨论】:

  • 你确定你的分隔符是 \n 而不是 CRLF \r\n?
  • 是的,上面的示例正文是使用 "\n" 拆分的,但是即使使用 "\r\n" 也会产生相同的结果。我可以在不解组的情况下对其进行流式传输,并且可以很好地使用“\n”进行节流
  • 如果您发送一个示例 CSV,比如 5 行,并在拆分和流式传输后记录正文,那么正文是什么样的?
  • [mel-1) 线程 #0 - file://data] route1 INFO HEADER_1;HEADER_2;HEADER_3;HEADER_4;HEADER_5 [mel-1) 线程 #0 - file://data] DefaultErrorHandler错误 (MessageId: ID-Admin-PC-60394-1473926738496-0-3 on ExchangeId: ID-Admin-PC-60394-1473926738496-0-4) 传递失败。交付尝试后用尽:1 捕获:java.lang.IllegalArgumentException:CSV 中没有定义记录
  • 有趣的是,我确实看到了 csv 记录;它读取每一行并在尝试解组时失败。

标签: apache-camel integration


【解决方案1】:

可能是您设置了 skipFirstLine = true 吗?但是由于您使用换行符进行拆分,因此跳过第一行意味着没有行可以解析 CSV。试试这个.split().tokenize("\n", 1000).streaming()。这基本上意味着我们想要基于标记“\n”进行拆分,并且我们想要将 N 行组合在一起。在这种情况下,它是 1000,因此它最多将 1000 行组合在一起。

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-20
    • 1970-01-01
    相关资源
    最近更新 更多