我正在尝试建立一个通用方法,将CSV文件解析为对象。
我想我已经很接近目标了,但是我对java泛型有点困,我还在学习。
现在我被困在创建对象的while循环中。我使用jCSV为我做解析。我在这里遵循他们的文档教程。
我不知道如何设置beanClass bc = it.next();
,因为beanClass
不存在作为一个类在我的项目,编译错误:cannot find symbol - class beanClass
我该如何解决这个问题?
我知道我可以简单地做一个List<?> beanClassList = csvFileReader.readAll();
但问题是,在每个CSV文件的第一行,我有数据所属的类名。我得到了这个异常,这是有意义的:
Exception in thread "AWT-EventQueue-0" java.lang.NumberFormatException: For input string: "Car"
我的CSV文件是这样的:
ClassName
value,value,value,value,value
value,value,value,value,value
...
下面是我的代码:
public String importFromCsvFile(File f) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
{
FileReader fr = new FileReader(f);
BufferedReader buffReader = new BufferedReader(fr);
String className = buffReader.readLine();
buffReader.close();
//Java reflection to get the Class Object.
Class beanClass = Class.forName("model." + className);
Object beanObject = beanClass.newInstance();
Reader reader = new FileReader(f);
ValueProcessorProvider provider = new ValueProcessorProvider();
CSVEntryParser<?> entryParser = new AnnotationEntryParser<>(beanClass, provider);
CSVReader<?> csvFileReader= new CSVReaderBuilder<>(reader).entryParser((CSVEntryParser<Object>) entryParser).build();
Iterator<?> it = csvFileReader.iterator();
while (it.hasNext()) {
beanClass bc = it.next(); // here is the compilation error
}
}
下面是一个CSV文件示例:
Car
1,BMW,Z3,2000,20-AC-57
2,Mercedes,C4,2010,23-32-VJ
3,Alfa Romeo,A3,1992,XX-XX-XX
你就快成功了。
public String importFromCsvFile(File f) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
{
FileReader fr = new FileReader(f);
BufferedReader buffReader = new BufferedReader(fr);
String className = buffReader.readLine();
buffReader.close(); // you can also not close it and use buffReader as your reader for the CSV
//Java reflection to get the Class Object.
Class beanClass = Class.forName("model." + className);
Object beanObject = beanClass.newInstance(); // this is never needed
Reader reader = new FileReader(f); // use buffReader instead of creating a new one
ValueProcessorProvider provider = new ValueProcessorProvider();
CSVEntryParser<?> entryParser = new AnnotationEntryParser<>(beanClass, provider);
CSVReader<?> csvFileReader= new CSVReaderBuilder<>(reader).entryParser((CSVEntryParser<Object>) entryParser).build();
Iterator<?> it = csvFileReader.iterator();
while (it.hasNext()) {
Object obj = it.next(); // obj is an instance of Car with your data
boolean isCar = obj instanceof Car; // will be true
}
}
因为你使用,
作为分隔符,你应该考虑使用UK_DEFAULT
作为Reader的策略,或者定义你自己的(默认的分隔符是;
)。
您还应该继续使用BufferedReader或在策略中指定skipHeader
-否则您的Car
将被视为条目,这可能不是您想要的。
根据您的评论,请查看从CSV文件读取数据并将其存储在映射中作为键值对的示例代码。
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
BufferedReader reader = new BufferedReader(new FileReader(new File("resources/abc.csv")));
String header = reader.readLine();
String[] keys = header.split(",");
String line = null;
while ((line = reader.readLine()) != null) {
Map<String, String> map = new HashMap<String, String>();
String[] values = line.split(",");
for (int i = 0; i < keys.length; i++) {
map.put(keys[i], values[i]);
}
list.add(map);
}
reader.close();
for(Map<String, String> map:list){
for(String key:map.keySet()){
System.out.println(key+":"+map.get(key));
}
System.out.println();
}
CSV: ID,NAME,MODEL,YEAR,NUMBER
1,BMW,Z3,2000,20-AC-57
2,Mercedes,C4,2010,23-32-VJ
3,Alfa Romeo,A3,1992,XX-XX-XX
对于泛型,类型在编译时指定(并由编译器检查)。在您的示例中,类型仅在CSV文件中指定,因此在编译时是未知的。所以在这种情况下,你不能使用泛型。
你到底想用泛型完成什么?您希望编译器检查什么?
可以做的是使用Class.forName(name).newInstance()
创建类的实例(您将需要一个完整的名称,包括包),并使用反射来设置一些属性。但是在编译时,您将只知道结果是一个Object
。