创建通用CsvReader

时间:2010-09-19 18:26:40

标签: java

我正在尝试创建一个简单的类来读取csv文件并将内容存储在

ArrayList<ArrayList<T>>.  

我正在创建一个泛型类CsvReader,以便我可以处理不同类型的数据:int,double,String。如果我有一个双打的csv文件,我想象我会像这样使用我的课程:

//possible method 1
CsvReader<Double> reader = new CsvReader<Double>();
ArrayList<ArrayList<Double>> contents = reader.getContents();

//possible method 2
CsvReader reader = new CsvReader(Double.class);
ArrayList<ArrayList<Double>> contents = reader.getContents();

但是方法1不起作用,因为类型擦除会阻止您编写像

这样的代码
rowArrayList.add(new T(columnStringValue)); 

但我甚至无法在Double.class解决方案中进行传递。问题是,真正发生的是我需要在具有以下属性的类型上“参数化”(在一般意义上,不是技术java泛型的意义上):它有一个接受单个String参数的ctor 。也就是说,要在Double csv文件上创建行ArrayLists,我需要写:

StringTokenizer st = new StringTokenizer(line,",");
ArrayList<Double> curRow = new ArrayList<Double>();
while (st.hasMoreTokens()) {
 curRow.add(new Double(st.nextToken());
}

传入Double.class后,我可以使用

获取String ctor
  Constructor ctor = c.getConstructor(new Class[] {String.class});

但这有两个问题。最重要的是,这是一个将返回类型Object的通用构造函数,然后我无法将其转换为Double。其次,我将缺少“类型”检查,因为我要求我传入类中有一个String arg构造函数。

我的问题是:如何正确实现此通用CsvReader?

谢谢, 约拿

4 个答案:

答案 0 :(得分:7)

我不确定通用的CSV阅读器是否会如此简单易用(顺便说一句,也可以创建)。

我想到的第一个问题是:如果CSV包含三列,那么该怎么办:首先是整数,然后是字符串,最后是日期?您将如何使用通用CSV阅读器?

无论如何,假设您要创建一个CSV阅读器,其中所有列都属于同一类型。正如您所说,您无法在“接受String作为构造函数”的类型上对类进行参数化。 Java只是不允许这样做。使用反射的解决方案是一个良好的开端。但是如果你的类没有在其构造函数中使用String作为参数呢?

在这里,你可以选择另一种方法:一个解析器,它将获取你的String并返回一个正确类型的对象。创建一个通用接口,并为要爬网的类型进行一些实现:

public interface Parser<T> {

    T parse(String value);

}

然后,实施:

public class StringParser implements Parser<String> {

    public String parse(String value) {
        return value;
    }

}

然后,您的CSV阅读器可以将Parser作为其参数之一。然后,它可以使用此解析器将每个String转换为Java对象。

使用此解决方案,您可以摆脱使用时不那么漂亮的反射。您可以转换为任何类型,只需实现Parser

您的读者将会是这样的:

public CSVReader<T> {

    Parser<T> parser;

    List<T> getValues() {
        // ...
    }

}

现在,回到CSV文件可以有多种类型的问题,只需稍微改进您的阅读器。您只需要一个解析器列表(每列一个),而不是解析所有列的解析器。

希望有所帮助: - )

答案 1 :(得分:1)

如果您正在尝试做实际工作,我建议您忘记并使用Scanner

如果你正在试验:我会把CsvReader变成一个抽象类:

public abstract class  CsvReader<T> {
...
    // This is what you use in the rest of CsvReader
    // to create your objects from the strings in the CSV
    protected abstract T parse(String s);
...
}

它将用作:

CsvReader<Double> = new CsvReader<Double>() {
    @Override protected Double parse(String s) {
        return Double.valueOf(s);
    }
};
...

不完美,但合理。


编辑:事实证明你可以按照自己的方式使用它,虽然它看起来有点像hackish。见Super Type Tokens。它基本上包括在CsvReader中包含超类型标记链接中显示的逻辑,以便可以获得与您的元素类对应的类对象。

答案 2 :(得分:1)

创建正确 CVS阅读器可能比您想象的更困难。例如,在您的代码示例中,在以下情况下它将无法正常工作。

  

“Microsoft,Inc”,1,2,3

而不是4个字段,您将得到的是基于

的5个字段
StringTokenizer st = new StringTokenizer(line,",");

我的建议是,使用第三方库实现。例如

http://opencsv.sourceforge.net/

我在我的一个应用程序中使用它,我的应用程序已经运行了3年。到目前为止一切都很好。

答案 3 :(得分:0)

我需要读取存储在CSV文件单元格中的简单字符串列表,并开始搜索Java解决方案。我发现大多数开源CSV阅读器对我来说都是不必要的复杂。 (有关全面审核,请参阅https://agiletribe.wordpress.com/2012/11/23/the-only-class-you-need-for-csv-files/)。 最后我发现MKYong的代码非常有效。为了我的目的,我必须调整它以读取整个CSV或TSV文件并将其作为列表列表返回。内部列表中的每个元素代表CSV的一个单元格。代码以及MKYong的信誉可以在以下位置找到: https://github.com/ramanraja/CsvReader