我有多个包含大约200到300列的csv文件,我需要使用一对一的映射创建pojos(列也是java类字段)。别担心不推荐的事实。 如果您知道某个工具或如何自动执行此操作,请投入。
所以你有一个csv文件,包含数千个包含数百列的行,第一行包含列的标题。所以我需要的是,基于第一行(列的标题)来创建一个包含这些标题作为类字段的java类。别介意实际数据。我只需要一个包含这些字段的java类
关于这个帖子有一个问题,但大约在3年前被问到,所以我想已经过时了。
答案 0 :(得分:6)
您可以使用Javassist在运行时生成类:
<强>代码:强>
public static void main(String[] args) throws Exception {
String[] fieldNames = null;
Class<?> rowObjectClass = null;
try(BufferedReader stream = new BufferedReader(new InputStreamReader(Program.class.getResourceAsStream("file.csv")))) {
while(true) {
String line = stream.readLine();
if(line == null) {
break;
}
if(line.isEmpty() || line.startsWith("#")) {
continue;
}
if(rowObjectClass == null) {
fieldNames = line.split(",");
rowObjectClass = buildCSVClass(fieldNames);
} else {
String[] values = line.split(",");
Object rowObject = rowObjectClass.newInstance();
for (int i = 0; i < fieldNames.length; i++) {
Field f = rowObjectClass.getDeclaredField(fieldNames[i]);
f.setAccessible(true);
f.set(rowObject, values[i]);
}
System.out.println(reflectToString(rowObject));
}
}
}
}
private static int counter = 0;
public static Class<?> buildCSVClass(String[] fieldNames) throws CannotCompileException, NotFoundException {
ClassPool pool = ClassPool.getDefault();
CtClass result = pool.makeClass("CSV_CLASS$" + (counter++));
ClassFile classFile = result.getClassFile();
ConstPool constPool = classFile.getConstPool();
classFile.setSuperclass(Object.class.getName());
for (String fieldName : fieldNames) {
CtField field = new CtField(ClassPool.getDefault().get(String.class.getName()), fieldName, result);
result.addField(field);
}
classFile.setVersionToJava5();
return result.toClass();
}
public static String reflectToString(Object value) throws IllegalAccessException {
StringBuilder result = new StringBuilder(value.getClass().getName());
result.append("@").append(System.identityHashCode(value)).append(" {");
for (Field f : value.getClass().getDeclaredFields()) {
f.setAccessible(true);
result.append("\n\t").append(f.getName()).append(" = ").append(f.get(value)).append(", ");
}
result.delete(result.length()-2, result.length());
return result.append("\n}").toString();
}
<强>资源:强>
file.csv(classpath):
############
foo,bar
############
hello,world
cafe,babe
<强>输出:强>
CSV_CLASS$0@1324706137 {
foo = hello,
bar = world
}
CSV_CLASS$0@1373076110 {
foo = cafe,
bar = babe
}
答案 1 :(得分:1)
根据我的不足,您正在尝试读取包含大量列的csv文件,将其视为数据库表
我的解决方案如下
这可以通过使用文件作为数据源和csvjdbc驱动程序来完成,并使用元数据,您可以检索所有列
可以这样做,参考位于 here
答案 2 :(得分:1)
此版本不使用任何花哨的类生成代码;相反,它输出Java源文件(或更准确地说,单个类文件,CSV中每个非标题行的静态公共内部子类)。
以下输入(从Binkan借来):
############
foo,bar
############
he"l\nl"o,world
cafe,babe
输出结果为:
public class Out {
public static class Row1 {
public String foo = "he\"l\\nl\"o";
public String bar = "world";
}
public static class Row2 {
public String foo = "cafe";
public String bar = "babe";
}
}
这是代码;部分改编自Binkan关于逐行阅读:
public class T {
public static void classesFromRows(String fileName, PrintWriter out, String classNamePrefix) throws Exception{
try(BufferedReader stream = new BufferedReader(new FileReader(fileName))) {
String line = null;
String[] fields = null;
int rowNum = 0;
while ((line = stream.readLine()) != null) {
if (line.isEmpty() || line.startsWith("#")) {
// do nothing
} else if (fields == null) {
fields = line.split(",");
} else {
rowNum ++;
String[] values = line.split(",");
out.println("\tpublic static class " + classNamePrefix + rowNum + " {");
for (int i=0; i<fields.length; i++) {
out.println("\t\tpublic String " + fields[i] + " = \""
+ StringEscapeUtils.escapeJava(values[i]) + "\";");
}
out.println("\t}");
}
}
}
}
// args[0] = input csv; args[1] = output file
public static void main(String[] args) throws Exception {
File outputFile = new File(args[1]);
String outputClass = outputFile.getName().replace(".java", "");
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(outputFile)));
// missing: add a package here, if you want one
out.println("public class " + outputClass + " {");
classesFromRows(args[0], out, "Row");
out.println("}");
out.close();
}
}
我选择将所有数据都视为字符串(从好的方面来说,我正在使用StringEscapeUtils正确地逃避它们);使用更多代码,您可以指定其他类型。