我有一组下面的对象,我需要将它们写入CSV:
public class OutputObject {
private String userId;
private Map<String, Object> behaviour;
}
上面的集合可以有一个具有两个、三个或四个值的映射。
[
OutputObject1 [userId=11, behaviours={color=white, size=S, owner=Mr. A}],
OutputObject2 [userId=22, behaviours={color=black, isNew=true}],
OutputObject3 [userId=33, behaviours={color=green, size=L}]
]
所需CSV输出:
userId, color, size, owner, isNew
11, white, S, Mr. A,
22, black, , , true
33, green, L, ,
我从下面的片段开始打印:
// Set<OutputObject> outputObjectSet already received.
JSONArray jsonArrayObject = new JSONArray(outputObjectSet);
String csvValue = CDL.toString(jsonArrayObject);
FileWriter fileWriter = new FileWriter(fileObject, true);
fileWriter.write(csvValue);
fileWriter.close();
但上面是创建一个两列csv,带有userId和行为打印所有地图对象 的行为由于集合中可能包含大量这样的对象,如何才能有效地做到这一点。
使用JSONArray在这里似乎是多余的,您可以实现一个助手方法,将OutputObject
序列化为CSV字符串,同时考虑到需要维护列的顺序:
public class CSVSerializer {
public static String transform(OutputObject obj) {
String[] fields = {"color", "size", "owner", "isNew"};
return Stream.concat(
Stream.of(obj.getUserId()),
Arrays.stream(fields)
.map(f -> obj.getBehaviour().get(f))
.map(v -> v == null ? "" : v.toString())
)
.collect(Collectors.joining(","));
}
}
String csv = outputObjectSet.stream()
.map(CSVSerializer::transform)
.collect(Collectors.joining("n"));
// print csv contents
由于Java的HashMap
和Arrays.sort()
实现非常快,因此即使使用更多的对象,这也应该非常高效。请注意,此实现依赖于Apache的common-text
-库来转义内容。
private static void outputCSV(List<OutputObject> objects, PrintStream output) {
AtomicInteger highestBehaviourIndex = new AtomicInteger();
HashMap<String, Integer> behaviourIndexMap = new HashMap<>();
// Give every behaviour an index
for (OutputObject object : objects) {
object.getBehaviour().forEach((name, value) -> behaviourIndexMap.computeIfAbsent(name, (unused) -> highestBehaviourIndex.getAndIncrement()));
}
String[] behaviours = new String[highestBehaviourIndex.get()];
behaviourIndexMap.forEach((name, index) -> {
behaviours[index] = name;
});
output.println("userId, " + String.join(", ", behaviours));
// Sort by ID
objects.sort(Comparator.comparingInt(OutputObject::getUserId));
for (OutputObject object : objects) {
// Print line
StringJoiner joiner = new StringJoiner(", ");
for (String behaviour : behaviours) {
joiner.add(StringEscapeUtils.escapeCsv(object.getBehaviour().getOrDefault(behaviour, "").toString()));
}
output.println(object.getUserId() + ", " + joiner.toString());
}
}