如何从csv文件生成java类

时间:2015-05-28 11:49:14

标签: java csv

我有多个包含大约200到300列的csv文件,我需要使用一对一的映射创建pojos(列也是java类字段)。别担心不推荐的事实。 如果您知道某个工具或如何自动执行此操作,请投入。

所以你有一个csv文件,包含数千个包含数百列的行,第一行包含列的标题。所以我需要的是,基于第一行(列的标题)来创建一个包含这些标题作为类字段的java类。别介意实际数据。我只需要一个包含这些字段的java类

关于这个帖子有一个问题,但大约在3年前被问到,所以我想已经过时了。

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查询数据列

这可以通过使用文件作为数据源和csvjdbc驱动程序来完成,并使用元数据,您可以检索所有列

  • 使用工具提供程序
  • 创建运行时POJO类

可以这样做,参考位于 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正确地逃避它们);使用更多代码,您可以指定其他类型。