我有以下格式的CSV:
New CSV file
header_1,header_2,header_3,header_4
value_1,value_2,value_3,value_4
value_1,value_2,value_3,value_4
value_1,value_2,value_3,value_4
我有以下用于解析此CSV的代码:
CsvMapper csvMapper = new CsvMapper();
CsvSchema schema = CsvSchema.emptySchema().withSkipFirstDataRow(true);
List<CsvModel> rows = new LinkedList<>();
MappingIterator<CsvModel> iterator = csvMapper
.readerFor(CsvModel.class).with(schema)
.readValues(filePath.toFile());
while (iterator.hasNext()) {
CsvModel csvElement = iterator.next();
if (StringUtils.isBlank(csvElement.getValue1())) {
// skip lines not having the value
continue;
}
rows.add(csvElement);
}
但是,在解析上述CSV格式文件时,我收到以下异常:
com.fasterxml.jackson.databind.RuntimeJsonMappingException: Can not construct instance of com.adapters.CsvParsing: no String-argument constructor/factory method to deserialize from String value ('')
at [Source: com.fasterxml.jackson.dataformat.csv.impl.UTF8Reader@2cb566f1; line: 2, column: 1]
这是因为第二行是空的。我需要跳过前两行,如何告诉jackson跳过文件的前两行?
编辑1: 这是CsvModel文件:
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class CsvModel {
public static final String IdField = "Id";
public static final String NameField = "Name";
public static final String GuidField = "Guid";
public static final String SubscriptionNameField = "Subscription Name";
public static final String DateField = "Date";
public static final String CostField = "Cost";
@JsonProperty(IdField)
private String Id;
@JsonProperty(NameField)
private String Name;
@JsonProperty(GuidField)
private String Guid;
@JsonProperty(SubscriptionNameField)
private String SubscriptionName;
@JsonProperty(DateField)
private String Date;
private Long epochDate;
@JsonProperty(CostField)
private Double Cost;
public String getId() {
return this.Id;
}
public void setId(String id) {
this.Id = id;
}
public String getName() {
return this.Name;
}
public void setName(String name) {
this.Name = name;
}
public String getGuid() {
return this.Guid;
}
public void setGuid(String guid) {
this.Guid = guid;
}
public String getSubscriptionName() {
return this.SubscriptionName;
}
public void setSubscriptionName(String subscriptionName) {
this.SubscriptionName = subscriptionName;
}
public String getDate() {
return this.Date;
}
public void setDate(String date) {
this.Date = date;
}
public Long getEpochDate() {
return this.epochDate;
}
public void setEpochDate(Long epochDate) {
this.epochDate = epochDate;
}
public Double getCost() {
return this.Cost;
}
public void setCost(Double cost) {
this.Cost = cost;
}
}
答案 0 :(得分:2)
要跳过空行,可以使用SKIP_EMPTY_LINES功能:
CsvMapper csvMapper = new CsvMapper().enable(CsvParser.Feature.SKIP_EMPTY_LINES);
CsvSchema schema = csvMapper.emptySchema().withSkipFirstDataRow(true);
MappingIterator<Account> dataIterator = csvMapper.readerFor(CsvModel.class).with(schema)
.readValues(file);
答案 1 :(得分:1)
您可以在处理前将迭代器提前两次跳过前两行,例如:
for(int i=0 ; i<2 ; i++){
if(iterator.hasNext()){
iterator.next();
}
}
while (iterator.hasNext()) {
...
如果假设该文件少于2条记录,这将确保不会抛出Exception
。
<强>更新强>
根据问题编辑编辑答案:
它抛出RuntimeJsonMappingException
的原因是因为它将一行vsc文件解释为字符串并且正在尝试将String
绑定到CsvModel
对象。您需要使用schema
映射器指定(非空)csvMapper
,并在反序列化一行时充当metadata
,例如:
CsvSchema schema = CsvSchema.builder()
.setColumnSeparator(',')
.addColumn("Id")
.addColumn("name")
....
您可以查看this示例。
答案 2 :(得分:0)
一个更好的答案是使用BufferedReader.readLine()
消耗前几行。
请参阅此Apache commons csv skip lines。
示例代码:
try (final BufferedReader reader = new BufferedReader(new FileReader(csvFile))) {
// consume the first few lines here
reader.readLine();
reader.readLine();
final MappingIterator<MyClass> readValues =
new CsvMapper()
.readerFor(MyClass.class)
.with(emptySchema()
.withHeader()
.withNullValue(""))
.readValues(reader);
final List<MyClass> records = readValues.readAll();
} catch (Exception e) {
log.warn("Failed to read detail section of transactionItem file.");
}