是否有一种简单的方法来输出逐列CSV?

我正在尝试将多个不同长度的数据列表输出到CSV文件。 每个列表应该是输出CSV文件中的一列。 做事的直接方式有吗? 如果我将每个列表作为一行输出,我只是遍历每个列表并在结束时输出一个返回,但是这种方法在按列工作时不起作用。

我想要一次又一次地遍历所有列表,逐项递增计数器,但这也会失败,因为有些列表比其他列表长。 为了解决这个问题,我必须在每次迭代时检查计数器是否超过每个列表的末尾,这在计算方面相当昂贵。

谢谢你的任何想法!

我认为这很简单:

public static void main(String... args) throws IOException { ArrayList> rows = getRandomData(); if (rows.size() == 0) throw new RuntimeException("No rows"); // normalize data int longest = 0; for (List row : rows) if (row.size() > longest) longest = row.size(); for (List row : rows) while (row.size() < longest) row.add(""); if (longest == 0) throw new RuntimeException("No colums"); // fix special characters for (int i = 0; i < rows.size(); i++) for (int j = 0; j < rows.get(i).size(); j++) rows.get(i).set(j, fixSpecial(rows.get(i).get(j))); // get the maximum size of one column int[] maxColumn = new int[rows.get(0).size()]; for (int i = 0; i < rows.size(); i++) for (int j = 0; j < rows.get(i).size(); j++) if (maxColumn[j] < rows.get(i).get(j).length()) maxColumn[j] = rows.get(i).get(j).length(); // create the format string String outFormat = ""; for (int max : maxColumn) outFormat += "%-" + (max + 1) + "s, "; outFormat = outFormat.substring(0, outFormat.length() - 2) + "\n"; // print the data for (List row : rows) System.out.printf(outFormat, row.toArray()); } private static String fixSpecial(String s) { s = s.replaceAll("(\")", "$1$1"); if (s.contains("\n") || s.contains(",") || s.contains("\"") || s.trim().length() < s.length()) { s = "\"" + s + "\""; } return s; } private static ArrayList> getRandomData() { ArrayList> data = new ArrayList>(); String[] rand = { "Do", "Re", "Song", "David", "Test", "4", "Hohjoh", "a \"h\" o", "tjo,ad" }; Random r = new Random(5); for (int i = 0; i < 10; i++) { ArrayList row = new ArrayList(); for (int j = 0; j < r.nextInt(10); j++) row.add(rand[r.nextInt(rand.length)]); data.add(row); } return data; } 

输出(非常丑陋,因为它随机)( 转义 ):

 Re , 4 , "tjo,ad" , "tjo,ad" , "tjo,ad" , "a ""h"" o" , , , Re , "a ""h"" o" , Hohjoh , "tjo,ad" , 4 4 , David , , , 4 , Test , "tjo,ad" , Hohjoh , Re Do , Hohjoh , Test , , Hohjoh , Song , , , 4 , Song , , , 4 , Do , Song , Do , Song , Test , Test , , 

值得一看http://commons.apache.org/sandbox/csv/

这也引用了一些其他CSV库。

请注意,许多答案都没有考虑包含逗号的字符串。 这就是为什么图书馆比自己做的更好的原因。

您可以使用String.format():

 System.out.println(String.format("%4s,%4s,%4s", "a", "bb", "ccc")); System.out.println(String.format("%4s,%4s,%4s", "aaa", "b", "c")); 

结果将是4个字符的固定列宽 – 只要使用的值更短。 否则布局会中断。

  a, bb, ccc aaa, b, c 

我根本不熟悉Java,但是如果你有一个面向matrix的数据类型,你可以使用简单的循环来填充行,然后转置它,然后使用简单的循环将其写出来。 您的打印例程可以通过输出空字符串或固定宽度空格来处理空条目(如果您愿意)。

创建一个迭代器数组(每个列表一个。)然后遍历数组,检查迭代器是否hasNext() ; 如果是,输出iterator.next() 。 输出逗号和换行是微不足道的。 当所有迭代器都返回hasNext()==false时停止。

你可以这样做:

 List> listOfLists = new LinkedList>(); List> listOfIterators = new LinkedList>(); for (List aList : listOfLists) { listOfIterators.add(aList.iterator()); } boolean done = false; while(!done) { done = true; for (Iterator iter : listOfIterators) { if (iter.hasNext()) { Object obj = iter.next(); //PROCESS OBJ done = false; } else { //PROCESS EMPTY ELEMENT } } } 

对于CSV处理,我多次使用过这个库: http : //www.csvreader.com/java_csv.php非常简单方便。

Cheerz!

我必须在每次迭代时检查计数器是否超过每个列表的末尾,这在计算方面相当昂贵。

克服它。 实际上,与实际进行迭代的成本相比,这将是很小的,与将任何给定的文本位写入文件的成本相比,这反过来会很小。 至少,假设你有随机访问容器。

但是你不应该考虑计数器和索引; 你应该考虑迭代器(避开随机访问问题并简化代码)。

如果您想在一对循环和一个方法中执行此操作,则可以执行以下操作。

 public static void writeCSV(PrintWriter pw, List> columnsRows) { for(int i=0;;i++) { StringBuilder line = new StringBuilder(); boolean empty = true; for (List column : columnsRows) { String text = i < column.size() ? column.get(i) : ""; found &= i >= column.size(); if (text.contains(",") || text.contains("\"") || text.contains("\n") || text.trim() != text) text = '"' + text.replaceAll("\"", "\"\"") + '"'; line.append(text).append(','); } if (empty) break; pw.println(line.substring(0, line.length()-1)); } } 

作为一个练习,你可以用一个循环来完成这个练习,但它不会像它做的那样清楚。

使用来自@dacwe的样本数据,此方法需要10 us(微秒)。