如何使用Jackson CSV忽略全空值行?
解决Jackson CSV忽略全空行(含全分隔符行)的问题
Jackson CSV的SKIP_EMPTY_LINES配置仅会跳过完全无字符的纯换行空行,对于你提到的,,或'','',''这类由分隔符/空引号组成的"全空行",它会被识别为包含空字符串字段的有效行,因此不会自动过滤。以下是几种可行的解决方案:
1. 遍历手动过滤(最直接)
在使用MappingIterator遍历POJO时,手动判断当前对象是否所有字段均为空,过滤掉这类无效对象:
首先定义你的POJO:
public class User { private String id; private String name; private String age; // 构造器、getter/setter 省略 }
然后在读取CSV时添加过滤逻辑:
CsvMapper mapper = new CsvMapper(); CsvSchema schema = mapper.schemaFor(User.class).withHeader(); List<User> validUsers = new ArrayList<>(); try (MappingIterator<User> iterator = mapper.readerFor(User.class).with(schema).readValues(csvFile)) { while (iterator.hasNext()) { User user = iterator.next(); // 判断所有字段是否为空,根据实际字段类型调整判断逻辑 if (!(StringUtils.isBlank(user.getId()) && StringUtils.isBlank(user.getName()) && StringUtils.isBlank(user.getAge()))) { validUsers.add(user); } } }
这里用了Apache Commons Lang的StringUtils,你也可以自己实现空值判断逻辑。
2. 自定义反序列化器(全局优雅处理)
通过BeanDeserializerModifier在反序列化完成后自动校验对象是否全空,返回null后再过滤:
public class EmptyBeanFilterModifier extends BeanDeserializerModifier { @Override public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) { if (beanDesc.getBeanClass() == User.class) { // 指定要处理的POJO类 return new EmptyBeanFilterDeserializer((JsonDeserializer<User>) deserializer); } return super.modifyDeserializer(config, beanDesc, deserializer); } private static class EmptyBeanFilterDeserializer extends DelegatingDeserializer { public EmptyBeanFilterDeserializer(JsonDeserializer<?> delegate) { super(delegate); } @Override protected JsonDeserializer<?> newDelegatingInstance(JsonDeserializer<?> newDelegatee) { return new EmptyBeanFilterDeserializer(newDelegatee); } @Override public User deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { User user = super.deserialize(p, ctxt); // 校验是否全空 if (StringUtils.isBlank(user.getId()) && StringUtils.isBlank(user.getName()) && StringUtils.isBlank(user.getAge())) { return null; } return user; } } }
然后注册这个修改器到CsvMapper:
CsvMapper mapper = new CsvMapper(); mapper.registerModule(new SimpleModule().setDeserializerModifier(new EmptyBeanFilterModifier())); CsvSchema schema = mapper.schemaFor(User.class).withHeader(); List<User> validUsers = mapper.readerFor(User.class).with(schema) .readValues(csvFile) .readAll() .stream() .filter(Objects::nonNull) .collect(Collectors.toList());
3. 预处理CSV文本(前置过滤)
在交给Jackson解析前,先过滤掉所有符合"全空行"特征的行:
// 读取CSV文本并过滤 String csvContent = Files.readString(Paths.get("your.csv")); // 正则匹配仅包含分隔符、引号和空白的行,替换为空 String filteredContent = csvContent.replaceAll("^\\s*(['\"]?\\s*,\\s*['\"]?)*\\s*$\\n?", "", Pattern.MULTILINE); // 再用Jackson解析过滤后的内容 CsvMapper mapper = new CsvMapper(); CsvSchema schema = mapper.schemaFor(User.class).withHeader(); List<User> validUsers = mapper.readerFor(User.class).with(schema) .readValue(filteredContent, new TypeReference<List<User>>() {});
以上三种方法都可以解决你的问题,根据实际场景选择即可。
内容的提问来源于stack exchange,提问作者Rohit Agarwal
相关产品推荐
相关产品推荐

