3

我有需要解析的不规则(尽管一致)“csv”文件。内容如下所示:

Field1: Field1Text
Field2: Field2Text

Field3 (need to ignore)
Field4 (need to ignore)

Field5
Field5Text

// Cars - for example
#,Col1,Col2,Col3,Col4,Col5,Col6
#1,Col1Text,Col2Text,Col3Text,Col4Text,Col5Text,Col6Text
#2,Col1Text,Col2Text,Col3Text,Col4Text,Col5Text,Col6Text
#3,Col1Text,Col2Text,Col3Text,Col4Text,Col5Text,Col6Text

理想情况下,我想使用与此处类似的方法。

我最终想得到一个像这样的对象:

String field1;
String field2;
String field5;
List<Car> cars;

我目前有以下问题:

  • 添加一些探索性测试后,以 hash(#) 开头的行将被忽略。我不要这个,有什么办法逃走吗?
  • 我的意图是对汽车部分使用 BeanListProcessor,并使用单独的行处理器处理其他字段。然后在上面提到的对象中组合结果。我在这里错过任何技巧吗?
4

1 回答 1

1

您的第一个问题是#默认情况下将其视为注释字符。要防止以开头的行#被视为注释,请执行以下操作:

parserSettings.getFormat().setComment('\0');

至于你正在解析的结构,没有办法开箱即用,但很容易利用 API 来实现它。以下将起作用:

    CsvParserSettings settings = new CsvParserSettings();
    settings.getFormat().setComment('\0'); //prevent lines starting with # to be parsed as comments

    //Creates a parser
    CsvParser parser = new CsvParser(settings);

    //Open the input
    parser.beginParsing(new File("/path/to/input.csv"), "UTF-8");

    //create BeanListProcessor for instances of Car, and initialize it.
    BeanListProcessor<Car> carProcessor = new BeanListProcessor<Car>(Car.class);
    carProcessor.processStarted(parser.getContext());

    String[] row;
    Parent parent = null;
    while ((row = parser.parseNext()) != null) { //read rows one by one.
        if (row[0].startsWith("Field1:")) {  // when Field1 is found, create your parent instance
            if (parent != null) { //if you already have a parent instance, cars have been read. Associate the list of cars to the instance
                parent.cars = new ArrayList<Car>(carProcessor.getBeans()); //copy the list of cars from the processor.
                carProcessor.getBeans().clear(); //clears the processor list
                //you probably want to do something with your parent bean here.
            }
            parent = new Parent(); //create a fresh parent instance
            parent.field1 = row[0]; //assign the fields as appropriate.
        } else if (row[0].startsWith("Field2:")) {
            parent.field2 = row[0]; //and so on
        } else if (row[0].startsWith("Field5:")) {
            parent.field5 = row[0];
        } else if (row[0].startsWith("#")){ //got a "Car" row, invoke the rowProcessed method of the carProcessor.
            carProcessor.rowProcessed(row, parser.getContext());
        }
    }

    //at the end, if there is a parent, get the cars parsed
    if (parent != null) {
        parent.cars = carProcessor.getBeans();
    }

为了BeanListProcessor工作,您需要像这样声明您的实例:

public static final class Car {
    @Parsed(index = 0)
    String id;
    @Parsed(index = 1)
    String col1;
    @Parsed(index = 2)
    String col2;
    @Parsed(index = 3)
    String col3;
    @Parsed(index = 4)
    String col4;
    @Parsed(index = 5)
    String col5;
    @Parsed(index = 6)
    String col6;
}

您可以改用标头,但它会让您编写更多代码。如果标题始终相同,那么您可以假设位置是固定的。

希望这可以帮助

于 2017-07-09T02:41:59.483 回答