我的第一个csv文件看起来像这样,包含标题(标题仅包含在顶部而不是每个条目之后):
NAME,SURNAME,AGE
Fred,Krueger,Unknown
.... n records
我的第二个文件可能如下所示:
NAME,MIDDLENAME,SURNAME,AGE
Jason,Noname,Scarry,16
.... n records with this header template
合并文件应如下所示:
NAME,SURNAME,AGE,MIDDLENAME
Fred,Krueger,Unknown,
Jason,Scarry,16,Noname
....
基本上如果标题不匹配,则应根据该顺序在原始标题及其值之后添加所有新标题标题(列)。
更新
上面的CSV变得更小,所以我可以说明我想要实现的目标,实际上CSV文件是在此之前生成的一步(合并),最多可以是100列
有谁知道我该怎么做?我很感激任何帮助
答案 0 :(得分:1)
我创建了一个'更大'格式的模型(一个包含四个字段的简单类和一个用于此类实例的集合)并实现了两个解析器,一个用于第一个,一个用于第二个模型。为两个csv文件的所有行创建记录,并实现编写器以正确的格式输出csv。简而言之:
public void convert(File output, File...input) {
List<Record> records = new ArrayList<Record>();
for (File file:input) {
if (input.isThreeColumnFormat()) {
records.addAll(ThreeColumnFormatParser.parse(file));
} else {
records.addAll(FourColumnFormatParser.parse(file));
}
}
CsvWriter.write(output, records);
}
从你的评论我看到,你有很多不同的csv格式和一些常见的列。
您可以为各种csv文件中的任何行定义模型,如下所示:
public class Record {
Object id; // some sort of unique identifier
Map<String, String> values; // all key/values of a single row
public Record(Object id) {this.id=id;}
public void put(String key, String value){
values.put(key, value);
}
public void get(String key) {
values.get(key);
}
}
对于解析任何文件,您首先要读取标题并将列标题添加到全局密钥库(稍后将需要输出),然后为所有行创建记录,如:
//...
List<Record> records = new ArrayList<Record>()
for (File file:getAllFiles()) {
List<String> keys = getColumnsHeaders(file);
KeyStore.addAll(keys); // the store is a Set
for (String line:file.getLines()) {
String[] values = line.split(DELIMITER);
Record record = new Record(file.getName()+i); // as an example for id
for (int i = 0; i < values.length; i++) {
record.put(keys.get(i), values[i]);
}
records.add(record);
}
}
// ...
现在密钥库已经全部使用了列标题名称,我们可以迭代所有记录的集合,获取所有键的所有值(如果此记录的文件没有使用密钥,则获取null
) ,组装csv行并将所有内容写入新文件。
答案 1 :(得分:1)
读入第一个文件的标题并创建列名列表。现在读取第二个文件的标题,并将列表中已存在的任何列名称添加到列表的末尾。现在,您按照所需的顺序排列了列,并且可以先将其写入新文件。
接下来我将解析每个文件,对于每一行,我将创建一个列名为Map的Map。解析行后,您可以迭代新的列名列表并从映射中提取值并立即将它们写入新文件。如果值为null,则不打印任何内容(如果需要,只显示逗号)。
可能有更高效的解决方案,但我认为这符合您的要求。
答案 2 :(得分:0)