2015-05-28 129 views
2

我有多个csv文件包含大约200到300列,我需要创建pojos与他们之间的映射一对一(列太Java类字段)。不要介意不推荐的事实。 如果您知道一个工具或如何自动执行此操作,请参阅。如何从csv文件生成java类

因此,您有一个csv文件,其中包含数百行包含数百个列的行,第一行包含列标题。所以我需要基于第一行(列标题)创建一个包含这些标题作为类字段的java类。没关系实际的数据。我只需要一个与这些领域的Java类

有一个关于这个帖子有些问题,但这是3年前问,所以我猜是过时了。

+0

您可以使用Javassist在运行时生成类 –

+0

您可以提供一个映射/ csv文件的一对一示例吗? –

+0

一个csv列应该生成一个类字段,所以255个csv列应该给我一个包含255个字段的类:) – aurelius

回答

4

可以使用了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(类路径):

############ 
foo,bar 
############ 
hello,world 
cafe,babe 


输出:

[email protected] { 
    foo = hello, 
    bar = world 
} 
[email protected] { 
    foo = cafe, 
    bar = babe 
} 
+2

我正在做同样的...我现在可以停止x) – romfret

+0

我对你的解决方案感兴趣:) –

+0

看起来像我的答案,我马上试试 – aurelius

1

按我undersatnding,你想读的大范围列的csv文件,而把它当作一个表数据库

我的解决方案如下

  • 使用csvjdbc查询的数据列

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

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

这是可以做到和refernce是 here

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正确逃脱他们);有了更多的代码,你可以指定其他类型。

+0

我不认为它打算把所有的行放在单独的类中,而不是用第一行中描述的字段来放置所有的行 –

+0

这是可能的;而且我的代码很容易修复来处理它。尽管如此,我认为上述代码或修订版本对任何人都不会有多大用处,除了证明编写原始源代码生成器是多么容易。 – tucuxi