Управление именами и позициями столбцов файлов при разборе CSV с Java - PullRequest
0 голосов
/ 03 апреля 2012

Я пишу некоторый код Java, который должен анализировать CSV-файлы с различными типами столбцов и значениями. Базовый файл выглядит примерно так (CSV) без строки заголовка / столбца. Чтобы упростить процесс обработки файла, я хочу иметь доступ к индексируемому значению каждой ячейки, используя имя столбца. В данный момент я не хочу использовать анализатор CSV .

    Column1 | Column2 | Column3 |...
    --------+---------+---------+---
    val10   | val20   | val30   |
    val11   | val21   | val31   |
    val12   | val22   | val32   |
    ...     | ...     | ...     |

Я думал об использовании ArrayList имен столбцов (по порядку), поскольку enum не конвертируется обратно в целые числа, как в C ++. Таким образом, я мог сделать что-то вроде:

    ArrayList<String> columnNames = new ArrayList<String>();
    columnNames.add("Column1");
    columnNames.add("Column2");
    columnNames.add("Column3");

    // read each line from the file ...
    String[] row = line.trim().split(",");
    String col2 = row[ columnNames.indexOf("Column2") ];

Я довольно новичок в Java - есть ли лучший / более умный способ сделать это? спасибо.

Ответы [ 3 ]

2 голосов
/ 03 апреля 2012

Ваш код работает.Тем не менее, если вы ищете «лучший» способ, вы можете переосмыслить два момента:

  1. indexOf (object) метод List не такой быстрый.стоит O (n).если вы поддерживаете Map<columnNameString, indexNumber> и получаете индекс из colName, он должен быть быстрее, чем ваш текущий impl.Кроме того, в Java вы можете получить различные типы значений из перечисления.вы даже можете позволить своему enum реализовывать интерфейсы.

  2. вам следует выполнить некоторую обработку исключений.Что делать, если в одной строке вашего файла отсутствуют (или более) столбцы.Ваши текущие коды будут выбрасывать исключение OutOfbound.однако я надеюсь, что это уже было сделано в ваших реальных кодах.

1 голос
/ 03 апреля 2012

Одно из ваших утверждений неточно. Вы утверждаете, что «enum не преобразует обратно в целые числа, как в C ++», что верно. Однако Enums в Java на самом деле более гибкие, чем это! Это объекты, которые могут иметь любое количество значений или свойств, а не просто число. Считайте этот (непроверенный) код:

public enum ColumnEnum {
    COL1(1),
    COL2(2),
    COL3(3);

    private final int index;
    ColumnEnum(int index) {
        this.index = index;
    }
    public double index()   { return index; }
}

Теперь вы можете ссылаться на части массива следующим образом:

// read each line from the file ...            
String[] row = line.trim().split(",");            
String col2 = row[ ColumnEnum.COL1.index() ];    
1 голос
/ 03 апреля 2012

Самый простой способ решить эту проблему - использовать библиотеку коллекций и создать список карт, где ключами карты являются имена столбцов, например:

List<Map<String,String>> records = someCodeForReadingDataFromFile();

Где вы разбиваете каждую строку вв массив, а затем создать карту значений:

List<Map<String,String>> someCodeForReadingDataFromFile() {
  List<<Map<String,String>> rowsList = new LinkedList<<Map<String,String>>();
  final String[] columnNames = {"Column1", "Column2", "Column3"};

  // add some loop to read one line at the time from the file
  ...
  String[] rows = line.trim().split(",");
  Map<String, String> rowMap = new HashMap<String, String>();
  for(int columnIndex = 0; columnIndex < columnNames.length; columnIndex++) {
     rowMap.put(columnNames[columnIndex], rows[columnIndex]); 
  }
  rowsList.add(rowMap);
  // repeat this until you reach EOF
  return rowsList;
}

Затем вы можете получить доступ ко всем ячейкам в CSV-файле, их индекс строки и имя столбца:

String valueOne = records.get(0).get("Column1"); // will set the value to "val10"

Если столбецимена являются фиксированными, вы все равно можете сделать перечисление, такое как

public enum Columns {
 Column1, Column2;
}

, а затем использовать метод name (), унаследованный от класса Enum, чтобы получить значения:

String valueOne = records.get(0).get(Columns.Column1);

Однако,если вы решите использовать библиотеку для упрощения этого процесса, я действительно могу порекомендовать библиотеку Smooks или даже Apache Commons CSV (действительно легкий!).

...