0

我正在编写一些应该解析具有不同列类型和值的 csv 文件的 java 代码。基本文件看起来像这样 (CSV),没有标题/列行。为了在处理文件时更简单,我希望能够使用列名访问每个单元格的索引值。我现在不想使用 CSV 解析器

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

我考虑过使用列名的 ArrayList(按顺序),因为枚举不会像 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相当陌生-有更好/更智能的方法吗?谢谢。

4

3 回答 3

2

您的代码有效。但是,如果您正在寻找“更好”的方式,您可能需要重新考虑两点:

  1. List 的 indexOf(object) 方法并没有那么快。成本 O(n)。如果您维护 aMap<columnNameString, indexNumber>并从 colName 获取索引,它应该比您当前的 impl 更快。除此之外,在 java 中,您可以从枚举中获取不同类型的值。你甚至可以让你的枚举实现接口。

  2. 你应该做一些异常处理。如果文件中的一行缺少一列(或多列)怎么办。您当前的代码将抛出 OutOfbound 异常。但是我希望这已经在你的真实代码中完成了。

于 2012-04-03T13:04:11.987 回答
1

解决这个问题的最简单方法是使用集合库并创建一个映射列表,其中映射中的键是列名,如下所示:

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;
}

然后使用继承自 Enum 类的 name() 方法获取值:

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

但是,如果您决定使用库来简化此过程,我真的可以推荐Smooks 库甚至Apache Commons CSV(真的很轻量级!)。

于 2012-04-03T12:48:58.677 回答
1

你的一个断言是不准确的。您声明“枚举不会像在 C++ 中那样转换回整数”,这是真的。然而,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() ];    
于 2012-04-03T12:53:54.247 回答