uniVocity не разбирает первый столбец на bean-компоненты

Я пытаюсь прочитать файлы CSV из GTFS.zip с помощью uniVocity-парсеров и столкнуться с проблемой, которую я не могу понять. По некоторым причинам кажется, что первый столбец некоторых CSV-файлов не будет проанализирован правильно. Например, в файле "stop.txt", который выглядит следующим образом:

stop_id,stop_name,stop_lat,stop_lon,location_type,parent_station
"de:3811:30215:0:6","Freiburg Stübeweg","48.0248455941735","7.85563688037231","","Parent30215"
"de:8311:30054:0:1","Freiburg Schutternstraße","48.0236251356332","7.72434519425597","","Parent30054"
"de:8311:30054:0:2","Freiburg Schutternstraße","48.0235446600679","7.72438739944883","","Parent30054"

Поле "stop_id" не будет проанализировано правильно, будет иметь значение "null"

Это метод, который я использую для чтения файла:

    public <T> List<T> readCSV(String path, String file, BeanListProcessor<T> processor) {
    List<T> content = null;
    try {
        // Get zip file
        ZipFile zip = new ZipFile(path);
        // Get CSV file
        ZipEntry entry = zip.getEntry(file);
        InputStream in = zip.getInputStream(entry);

        CsvParserSettings parserSettings = new CsvParserSettings();
        parserSettings.setProcessor(processor);
        parserSettings.setHeaderExtractionEnabled(true);

        CsvParser parser = new CsvParser(parserSettings);
        parser.parse(new InputStreamReader(in));
        content = processor.getBeans();

        zip.close();
        return content;

    } catch (Exception e) {
        e.printStackTrace();
    }
    return content;
}

А вот так выглядит мой стоп-класс:

public class Stop {
@Parsed
private String stop_id;
@Parsed
private String stop_name;
@Parsed
private String stop_lat;
@Parsed
private String stop_lon;
@Parsed
private String location_type;
@Parsed
private String parent_station;

public Stop() {
}

public Stop(String stop_id, String stop_name, String stop_lat, String stop_lon, String location_type,
        String parent_station) {
    this.stop_id = stop_id;
    this.stop_name = stop_name;
    this.stop_lat = stop_lat;
    this.stop_lon = stop_lon;
    this.location_type = location_type;
    this.parent_station = parent_station;
}

// --------------------- Getter --------------------------------
public String getStop_id() {
    return stop_id;
}

public String getStop_name() {
    return stop_name;
}

public String getStop_lat() {
    return stop_lat;
}

public String getStop_lon() {
    return stop_lon;
}

public String getLocation_type() {
    return location_type;
}

public String getParent_station() {
    return parent_station;
}

// --------------------- Setter --------------------------------
public void setStop_id(String stop_id) {
    this.stop_id = stop_id;
}

public void setStop_name(String stop_name) {
    this.stop_name = stop_name;
}

public void setStop_lat(String stop_lat) {
    this.stop_lat = stop_lat;
}

public void setStop_lon(String stop_lon) {
    this.stop_lon = stop_lon;
}

public void setLocation_type(String location_type) {
    this.location_type = location_type;
}

public void setParent_station(String parent_station) {
    this.parent_station = parent_station;
}

@Override
public String toString() {
    return "Stop [stop_id=" + stop_id + ", stop_name=" + stop_name + ", stop_lat=" + stop_lat + ", stop_lon="
            + stop_lon + ", location_type=" + location_type + ", parent_station=" + parent_station + "]";
    }
}

Если я вызываю метод, я получаю этот вывод, который не является правильным:

    PartialReading pr = new PartialReading();
    List<Stop> stops = pr.readCSV("VAGFR.zip", "stops.txt", new BeanListProcessor<Stop>(Stop.class));
    for (int i = 0; i < 4; i++) {
        System.out.println(stops.get(i).toString());
    }

Выход:

Stop [stop_id=null, stop_name=Freiburg Stübeweg, stop_lat=48.0248455941735, stop_lon=7.85563688037231, location_type=null, parent_station=Parent30215]
Stop [stop_id=null, stop_name=Freiburg Schutternstraße, stop_lat=48.0236251356332, stop_lon=7.72434519425597, location_type=null, parent_station=Parent30054]
Stop [stop_id=null, stop_name=Freiburg Schutternstraße, stop_lat=48.0235446600679, stop_lon=7.72438739944883, location_type=null, parent_station=Parent30054]
Stop [stop_id=null, stop_name=Freiburg Waltershofen Ochsen, stop_lat=48.0220902613143, stop_lon=7.7205756507492, location_type=null, parent_station=Parent30055]

Кто-нибудь знает, почему это происходит и как я могу это исправить? Это также происходит в файлах "rout.txt" и "trips.txt", которые я тестировал. Это файл GTFS: http://stadtplan.freiburg.de/sld/VAGFR.zip

1 ответ

Решение

Если вы напечатаете заголовки, вы заметите, что первый столбец выглядит неправильно. Это потому, что вы анализируете файл, закодированный с использованием UTF-8 с маркером спецификации.

В основном файл начинается с нескольких байтов, указывающих, что такое кодировка. До версии 2.5. * Парсер не обрабатывал это внутренне, и вам пришлось пропустить эти байты, чтобы получить правильный вывод:

//... your code here
ZipEntry entry = zip.getEntry(file);
InputStream in = zip.getInputStream(entry);

if(in.read() == 239 & in.read() == 187 & in.read() == 191){
    System.out.println("UTF-8 with BOM, bytes discarded");
}

CsvParserSettings parserSettings = new CsvParserSettings();
//...rest of your code here

Вышеуказанный хак будет работать на любой версии до 2.5.*, Но вы также можете использовать Commons-IO BOMInputStream для удобства и более чистой обработки такого рода вещей - это ОЧЕНЬ медленно.

Обновление до последней версии должно позаботиться об этом автоматически.

Надеюсь, поможет.

Другие вопросы по тегам