【问题标题】:How to serialize object to CSV file?如何将对象序列化为 CSV 文件?
【发布时间】:2011-04-09 14:57:24
【问题描述】:

我想将一个对象写入 CSV 文件。 对于 XML,我们有 XStream,例如 this
因此,如果我想将对象转换为 CSV,我们有没有这样的库?

编辑: 我想将我的 Bean 列表传递给应该将 bean 的所有字段写入 CSV 的方法。

【问题讨论】:

  • 可能更好的术语是编组/解组而不是序列化。 cos 将数据排列成所需格式(csv、xml、..)后,您可以将其保存在文件中。以下解决方案有效,但如果数据量很大,它们会出现性能问题。我的建议是使用 XSLT 文件作为 csv 模板格式化程序的转换器。

标签: java serialization csv object


【解决方案1】:

您可以使用 gererics 为任何类工作

public class FileUtils<T> {
public String createReport(String filePath, List<T> t) {
    if (t.isEmpty()) {
        return null;
    }

    List<String> reportData = new ArrayList<String>();

    addDataToReport(t.get(0), reportData, 0);

    for (T k : t) {
        addDataToReport(k, reportData, 1);
    }
    return !dumpReport(filePath, reportData) ? null : filePath;
}

public static Boolean dumpReport(String filePath, List<String> lines) {
    Boolean isFileCreated = false;

    
    String[] dirs = filePath.split(File.separator);
    String baseDir = "";
    for (int i = 0; i < dirs.length - 1; i++) {
        baseDir += " " + dirs[i];
    }
    baseDir = baseDir.replace(" ", "/");
    
    File base = new File(baseDir);
    base.mkdirs();

    File file = new File(filePath);
    try {
        if (!file.exists())
            file.createNewFile();
    } catch (Exception e) {
        e.printStackTrace();
        return isFileCreated;
    }

    try (BufferedWriter writer = new BufferedWriter(
            new OutputStreamWriter(new FileOutputStream(file), System.getProperty("file.encoding")))) {
        for (String line : lines) {
            writer.write(line + System.lineSeparator());
        }
    } catch (IOException e) {
        e.printStackTrace();
        return false;
    }
    return true;
}

void addDataToReport(T t, List<String> reportData, int index) {
    String[] jsonObjectAsArray = new Gson().toJson(t).replace("{", "").replace("}", "").split(",\"");
    StringBuilder row = new StringBuilder();

    for (int i = 0; i < jsonObjectAsArray.length; i++) {
        String str = jsonObjectAsArray[i];
        str = str.replaceFirst(":", "_").split("_")[index];

        if (i == 0) {
            if (str != null) {
                row.append(str.replace("\"", ""));
            } else {
                row.append("N/A");
            }
        } else {
            if (str != null) {
                row.append(", " + str.replace("\"", ""));
            } else {
                row.append(", N/A");
            }
        }
    }
    reportData.add(row.toString());
}

【讨论】:

    【解决方案2】:

    值得一提的是,handlebar 库https://github.com/jknack/handlebars.java 可以简化许多转换任务,包括 toCSV。

    【讨论】:

      【解决方案3】:

      虽然它的回复很晚,但我在各种项目中遇到了将 java 实体导出为 CSV、EXCEL 等的问题,我们需要在 UI 上提供导出功能。

      我创建了自己的轻量级框架。它适用于任何 Java Bean,您只需在要导出到 CSV、Excel 等的字段上添加注释。

      链接:https://github.com/abhisoni96/dev-tools

      【讨论】:

        【解决方案4】:

        拥有一个 csv 序列化器会很有趣,因为与其他序列化方法相比,它占用的空间最小。

        最接近csv的java对象支持是spring utils项目提供的stringutils

        arrayToCommaDelimitedString(Object[] arr) 但它远非序列化程序。

        这是一个使用反射序列化值对象的简单实用程序

        public class CSVWriter
        {
        private static String produceCsvData(Object[] data) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException
        {
            if(data.length==0)
            {
                return "";
            }
        
            Class classType = data[0].getClass();
            StringBuilder builder = new StringBuilder();
        
            Method[] methods = classType.getDeclaredMethods();
        
            for(Method m : methods)
            {
                if(m.getParameterTypes().length==0)
                {
                    if(m.getName().startsWith("get"))
                    {
                        builder.append(m.getName().substring(3)).append(',');
                    }
                    else if(m.getName().startsWith("is"))
                    {
                        builder.append(m.getName().substring(2)).append(',');
                    }
        
                }
        
            }
            builder.deleteCharAt(builder.length()-1);
            builder.append('\n');
            for(Object d : data)
            {
                for(Method m : methods)
                {
                    if(m.getParameterTypes().length==0)
                    {
                        if(m.getName().startsWith("get") || m.getName().startsWith("is"))
                        {
                            System.out.println(m.invoke(d).toString());
                            builder.append(m.invoke(d).toString()).append(',');
                        }
                    }
                }
                builder.append('\n');
            }
            builder.deleteCharAt(builder.length()-1);
            return builder.toString();
        }
        
        public static boolean generateCSV(File csvFileName,Object[] data)
        {
            FileWriter fw = null;
            try
            {
                fw = new FileWriter(csvFileName);
                if(!csvFileName.exists())
                    csvFileName.createNewFile();
                fw.write(produceCsvData(data));
                fw.flush();
            }
            catch(Exception e)
            {
                System.out.println("Error while generating csv from data. Error message : " + e.getMessage());
                e.printStackTrace();
                return false;
            }
            finally
            {
                if(fw!=null)
                {
                    try
                    {
                        fw.close();
                    }
                    catch(Exception e)
                    {
                    }
                    fw=null;
                }
            }
            return true;
        }
        

        }

        这是一个示例值对象

        public class Product {
        private String name;
        private double price;
        private int identifier;
        private boolean isVatApplicable;
        public Product(String name, double price, int identifier,
                boolean isVatApplicable) {
            super();
            this.name = name;
            this.price = price;
            this.identifier = identifier;
            this.isVatApplicable = isVatApplicable;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public double getPrice() {
            return price;
        }
        public void setPrice(long price) {
            this.price = price;
        }
        public int getIdentifier() {
            return identifier;
        }
        public void setIdentifier(int identifier) {
            this.identifier = identifier;
        }
        public boolean isVatApplicable() {
            return isVatApplicable;
        }
        public void setVatApplicable(boolean isVatApplicable) {
            this.isVatApplicable = isVatApplicable;
        }
        

        }

        以及运行 util 的代码

        public class TestCSV 
        {
        public static void main(String... a)
        {
            Product[] list = new Product[5];
            list[0] = new Product("dvd", 24.99, 967, true);
            list[1] = new Product("pen", 4.99, 162, false);
            list[2] = new Product("ipad", 624.99, 234, true);
            list[3] = new Product("crayons", 4.99,127, false);
            list[4] = new Product("laptop", 1444.99, 997, true);
            CSVWriter.generateCSV(new File("C:\\products.csv"),list);
        }
        
        }
        

        输出:

        Name    VatApplicable   Price   Identifier
        dvd     true            24.99   967
        pen     false           4.99    162
        ipad    true            624.99  234
        crayons false           4.99    127
        laptop  true            1444.99 997
        

        【讨论】:

        • 这看起来很有趣。但是,您是否将其用于大量数据?由于反射成本很高,我想知道是否有基准。谢谢
        【解决方案5】:

        首先,序列化是将对象“按原样”写入文件。 AFAIK,你不能选择文件格式和所有。序列化对象(在文件中)有自己的“文件格式”

        如果你想将一个对象(或对象列表)的内容写入CSV文件,你可以自己做,应该不会很复杂。

        看起来Java CSV Library可以做到这一点,但我自己没有尝试过。

        编辑:参见以下示例。这绝不是万无一失的,但您可以在此基础上再接再厉。

            //European countries use ";" as 
            //CSV separator because "," is their digit separator
            private static final String CSV_SEPARATOR = ",";
            private static void writeToCSV(ArrayList<Product> productList)
            {
                try
                {
                    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("products.csv"), "UTF-8"));
                    for (Product product : productList)
                    {
                        StringBuffer oneLine = new StringBuffer();
                        oneLine.append(product.getId() <=0 ? "" : product.getId());
                        oneLine.append(CSV_SEPARATOR);
                        oneLine.append(product.getName().trim().length() == 0? "" : product.getName());
                        oneLine.append(CSV_SEPARATOR);
                        oneLine.append(product.getCostPrice() < 0 ? "" : product.getCostPrice());
                        oneLine.append(CSV_SEPARATOR);
                        oneLine.append(product.isVatApplicable() ? "Yes" : "No");
                        bw.write(oneLine.toString());
                        bw.newLine();
                    }
                    bw.flush();
                    bw.close();
                }
                catch (UnsupportedEncodingException e) {}
                catch (FileNotFoundException e){}
                catch (IOException e){}
            }
        

        这是产品(为便于阅读而隐藏的 getter 和 setter):

        class Product
        {
            private long id;
            private String name;
            private double costPrice;
            private boolean vatApplicable;
        }
        

        这就是我的测试方式:

        public static void main(String[] args)
        {
            ArrayList<Product> productList = new ArrayList<Product>();
            productList.add(new Product(1, "Pen", 2.00, false));
            productList.add(new Product(2, "TV", 300, true));
            productList.add(new Product(3, "iPhone", 500, true));
            writeToCSV(productList);
        }
        

        希望这会有所帮助。

        干杯。

        【讨论】:

        • +1 写起来真的很简单,读起来有点难,但没那么多……如果输出值里面没有换行,读起来就变得很简单……
        • 不满足我的要求
        • @NewBie_Java:如果 Java CSV 库不能满足您的要求,您可以编写自己的逻辑。这并不困难,也没有害处……添加了一个关于如何执行此操作的简单逻辑。尝试以此为基础...
        【解决方案6】:

        我写了一个简单的类,它使用OpenCSV 并有两个static public 方法。

        static public File toCSVFile(Object object, String path, String name) {
            File pathFile = new File(path);
            pathFile.mkdirs();
            File returnFile = new File(path + name);
            try {
        
                CSVWriter writer = new CSVWriter(new FileWriter(returnFile));
                writer.writeNext(new String[]{"Member Name in Code", "Stored Value", "Type of Value"});
                for (Field field : object.getClass().getDeclaredFields()) {
                    writer.writeNext(new String[]{field.getName(), field.get(object).toString(), field.getType().getName()});
                }
                writer.flush();
                writer.close();
                return returnFile;
            } catch (IOException e) {
                Log.e("EasyStorage", "Easy Storage toCSVFile failed.", e);
                return null;
            } catch (IllegalAccessException e) {
                Log.e("EasyStorage", "Easy Storage toCSVFile failed.", e);
                return null;
            }
        }
        
        static public void fromCSVFile(Object object, File file) {
            try {
                CSVReader reader = new CSVReader(new FileReader(file));
                String[] nextLine = reader.readNext(); // Ignore the first line.
                while ((nextLine = reader.readNext()) != null) {
                    if (nextLine.length >= 2) {
                        try {
                            Field field = object.getClass().getDeclaredField(nextLine[0]);
                            Class<?> rClass = field.getType();
                            if (rClass == String.class) {
                                field.set(object, nextLine[1]);
                            } else if (rClass == int.class) {
                                field.set(object, Integer.parseInt(nextLine[1]));
                            } else if (rClass == boolean.class) {
                                field.set(object, Boolean.parseBoolean(nextLine[1]));
                            } else if (rClass == float.class) {
                                field.set(object, Float.parseFloat(nextLine[1]));
                            } else if (rClass == long.class) {
                                field.set(object, Long.parseLong(nextLine[1]));
                            } else if (rClass == short.class) {
                                field.set(object, Short.parseShort(nextLine[1]));
                            } else if (rClass == double.class) {
                                field.set(object, Double.parseDouble(nextLine[1]));
                            } else if (rClass == byte.class) {
                                field.set(object, Byte.parseByte(nextLine[1]));
                            } else if (rClass == char.class) {
                                field.set(object, nextLine[1].charAt(0));
                            } else {
                                Log.e("EasyStorage", "Easy Storage doesn't yet support extracting " + rClass.getSimpleName() + " from CSV files.");
                            }
                        } catch (NoSuchFieldException e) {
                            Log.e("EasyStorage", "Easy Storage fromCSVFile failed.", e);
                        } catch (IllegalAccessException e) {
                            Log.e("EasyStorage", "Easy Storage fromCSVFile failed.", e);
        
                        }
                    } // Close if (nextLine.length >= 2)
                } // Close while ((nextLine = reader.readNext()) != null)
            } catch (FileNotFoundException e) {
                Log.e("EasyStorage", "Easy Storage fromCSVFile failed.", e);
            } catch (IOException e) {
                Log.e("EasyStorage", "Easy Storage fromCSVFile failed.", e);
            } catch (IllegalArgumentException e) {
                Log.e("EasyStorage", "Easy Storage fromCSVFile failed.", e);
            }
        }
        

        我认为通过一些简单的递归可以修改这些方法以处理任何 Java 对象,但对我来说这已经足够了。

        【讨论】:

          【解决方案7】:

          【讨论】:

            【解决方案8】:

            为了方便 CSV 访问,有一个名为 OpenCSV 的库。它确实可以轻松访问 CSV 文件内容。

            编辑

            根据您的更新,我认为所有以前的回复都是不正确的(由于它们的低级别)。然后,您可以采用完全不同的方式,实际上是休眠方式!

            通过使用CsvJdbc 驱动程序,您可以加载您的CSV 文件作为JDBC 数据源,然后直接将您的bean 映射到此数据源。

            我会和你谈谈CSVObjects,但由于该网站似乎已损坏,我担心该库现在不可用。

            【讨论】:

            • OpenCSV 不满足我的要求
            • 我也有类似的要求。根据 API 文档,2.4 版有一个 BeanToCsv 类。不幸的是,好像 2.4 还没有发布。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-07-31
            • 1970-01-01
            • 1970-01-01
            • 2021-05-03
            • 1970-01-01
            相关资源
            最近更新 更多