【问题标题】:Validate every field in a single pass with SuperCSV使用 SuperCSV 一次性验证每个字段
【发布时间】:2012-11-18 18:40:16
【问题描述】:

我正在尝试使用 SuperCSV 将大量行(约 200 万行)从数据库写入 CSV 文件。我需要在编写每个单元格时对其执行验证,并且内置的 CellProcessors 做得非常好。我想捕获 CellProcessors 抛出的所有异常,以便我可以返回源数据并进行更改。

问题是当一行中有多个错误时(例如第一个值超出范围,第二个值为空但不应该),只有第一个 CellProcessor 会执行,所以我会只看到其中一个错误。我想一次性处理整个文件,并在其末尾有一套完整的异常。

这是我正在尝试的方法:

for (Row row : rows) {
    try {
        csvBeanWriter.write(row, HEADER_MAPPINGS, CELL_PROCESSORS);
    } catch (SuperCsvCellProcessorException e) {
        log(e);
    }
}

我怎样才能做到这一点?谢谢!

编辑:这是我编写的类似于 Hound Dog 的代码,以防它帮助任何人:

import java.util.List;

import org.supercsv.cellprocessor.CellProcessorAdaptor;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.exception.SuperCsvCellProcessorException;
import org.supercsv.util.CsvContext;

public class ExceptionCapturingCellProcessor extends CellProcessorAdaptor {

    private final List<Exception> exceptions;

    private final CellProcessor current;

    public ExceptionCapturingCellProcessor(CellProcessor current, CellProcessor next, List<Exception> exceptions) {
        super(next);
        this.exceptions = exceptions;
        this.current = current;
    }

    @Override
    public Object execute(Object value, CsvContext context) {
        // Check input is not null
        try {
            validateInputNotNull(value, context);
        } catch (SuperCsvCellProcessorException e) {
            exceptions.add(e);
        }

        // Execute wrapped CellProcessor
        try {
            current.execute(value, context);
        } catch (SuperCsvCellProcessorException e) {
            exceptions.add(e);
        }

        return next.execute(value, context);
    }
}

【问题讨论】:

  • 请注意,您不能将此处理器与ConvertNullTo 一起使用 - 您无需验证输入是否为空。 Super CSV 约定是将next 作为构造函数中的最后一个参数(因为它在长链中读起来更好)。

标签: java csv supercsv


【解决方案1】:

我推荐writing a custom CellProcessor 来实现这一点。可以将以下处理器放置在每个 CellProcessor 链的开头——它将简单地委托给链接在它之后的处理器,并抑制任何单元处理异常。

package example;

import java.util.ArrayList;
import java.util.List;
import org.supercsv.cellprocessor.CellProcessorAdaptor;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.exception.SuperCsvCellProcessorException;
import org.supercsv.util.CsvContext;

public class SuppressException extends CellProcessorAdaptor {

    public static List<SuperCsvCellProcessorException> SUPPRESSED_EXCEPTIONS = 
            new ArrayList<SuperCsvCellProcessorException>();

    public SuppressException(CellProcessor next) {
        super(next);
    }

    public Object execute(Object value, CsvContext context) {
        try {
            // attempt to execute the next processor
            return next.execute(value, context);

        } catch (SuperCsvCellProcessorException e) {
            // save the exception
            SUPPRESSED_EXCEPTIONS.add(e);

            // and suppress it (null is written as "")
            return null;
        }
    }
}

它正在发挥作用:

package example;

import java.io.StringWriter;
import java.util.Arrays;
import java.util.List;

import org.supercsv.cellprocessor.constraint.NotNull;
import org.supercsv.cellprocessor.constraint.StrMinMax;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.exception.SuperCsvCellProcessorException;
import org.supercsv.io.CsvBeanWriter;
import org.supercsv.io.ICsvBeanWriter;
import org.supercsv.prefs.CsvPreference;

public class TestSuppressExceptions {

    private static final CellProcessor[] PROCESSORS = {
            new SuppressException(new StrMinMax(0, 4)),
            new SuppressException(new NotNull()) };

    private static final String[] HEADER = { "name", "age" };

    public static void main(String[] args) throws Exception {

        final StringWriter stringWriter = new StringWriter();
        ICsvBeanWriter beanWriter = null;
        try {
            beanWriter = new CsvBeanWriter(stringWriter,
                    CsvPreference.STANDARD_PREFERENCE);

            beanWriter.writeHeader(HEADER);

            // set up the data
            Person valid = new Person("Rick", 43);
            Person nullAge = new Person("Lori", null);
            Person totallyInvalid = new Person("Shane", null);
            Person valid2 = new Person("Carl", 12);
            List<Person> people = Arrays.asList(valid, nullAge, totallyInvalid,
                    valid2);

            for (Person person : people) {
                beanWriter.write(person, HEADER, PROCESSORS);

                if (!SuppressException.SUPPRESSED_EXCEPTIONS.isEmpty()) {
                    System.out.println("Suppressed exceptions for row "
                                        + beanWriter.getRowNumber() + ":");
                    for (SuperCsvCellProcessorException e :
                                        SuppressException.SUPPRESSED_EXCEPTIONS) {
                        System.out.println(e);
                    }
                    // clear ready for next row
                    SuppressException.SUPPRESSED_EXCEPTIONS.clear();
                }

            }

        } finally {
            beanWriter.close();
        }

        // CSV will have empty columns for invalid data
        System.out.println(stringWriter);

    }

}

这是被抑制的异常输出(第 4 行有两个异常,每列一个):

Suppressed exceptions for row 3:
org.supercsv.exception.SuperCsvConstraintViolationException: null value 
encountered processor=org.supercsv.cellprocessor.constraint.NotNull
context={lineNo=3, rowNo=3, columnNo=2, rowSource=[Lori, null]}
Suppressed exceptions for row 4:
org.supercsv.exception.SuperCsvConstraintViolationException: the length (5) 
of value 'Shane' does not lie between the min (0) and max (4) values (inclusive)
processor=org.supercsv.cellprocessor.constraint.StrMinMax
context={lineNo=4, rowNo=4, columnNo=2, rowSource=[Shane, null]}
org.supercsv.exception.SuperCsvConstraintViolationException: null value 
encountered processor=org.supercsv.cellprocessor.constraint.NotNull
context={lineNo=4, rowNo=4, columnNo=2, rowSource=[Shane, null]}

还有 CSV 输出

name,age
Rick,43
Lori,
,
Carl,12

注意无效值是如何写成 "" 的,因为 SuppressException 处理器为这些值返回了 null(并不是说您无论如何都会使用 CSV 输出,因为它无效!)。

【讨论】:

  • 如果有人发现这样有用的东西,我会在即将发布的版本中添加它,这样你就不必自己编写了:)
  • 甜蜜!但该行仍被写入。我认为用于异常处理的专用钩子可能是更好的方法
  • 是的,请将它添加到版本中 - 向我推荐 SuperCSV 的人也遇到了这个!
  • 谢谢你。我把它做成了一个静态映射,这样它就可以保存内部错误的列号:catch (SuperCsvCellProcessorException e) { // 保存异常 CELL_EXCEPTIONS.put(e.getCsvContext().getColumnNumber(), e);
  • @AkberChoudhry 另一种方法是在保存异常之前用一个副本替换异常中的CsvContext(上下文被重用,因此您可能发现,所有异常都将引用相同的上下文如果你不这样做)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-17
  • 1970-01-01
  • 2012-09-29
  • 1970-01-01
  • 2011-03-29
相关资源
最近更新 更多