如何读取ItemReader中的所有行并将行和文件地址返回到ItemProcessor?

时间:2015-04-27 07:55:08

标签: java spring spring-batch batch-processing

我在批处理Spring项目中定义了一个作业流程,并定义了$f='data.txt'; $fh=fopen($f,'r+'); while (($l=fgets($fh))!==false) file_put_contents('tmp',clean($l),FILE_APPEND); fclose($f); unlink($f); rename('tmp',$f); ItemReaderItemProcessor等。

我的ItemWriter代码如下:

ItemReader

我的文件输入格式为:

@Component
@StepScope
public class MyFileReader extends FlatFileItemReader<FileInfo> {
    private String fileName;

    public MyFileReader () {
    }

    @Value("#{jobParameters[fileName]}")
    public void setFileName(final String fileName) {
        this.fileName = fileName;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Resource resource = new FileSystemResource(fileName);
        setResource(resource);
        setEncoding("UTF-8");
        super.afterPropertiesSet();
    }
}

我想阅读文件的所有行并将 行和文件地址 返回111111,11111,111,111 222222,22222,222,222 ,但是{{1}逐行读取。我该怎么做?是否重写ItemProcessor方法并手动处理问题?

1 个答案:

答案 0 :(得分:2)

如果我理解了这个问题,你想要从文件中读取所有行,将该数据存储在一个对象中,然后将所述对象传递给处理器。一种方法是在作业开始之前使用Job Listener读取文件中的所有行。如下图所示,您可以读取所有行,填充表示单行内容的Java对象,收集所有这些对象(如果有两行,则“填充2个bean”),然后传递它们一次一个处理器(如果你愿意,可能同时处理)。它看起来像这样:

  1. 首先,您将创建一个侦听器。

    public class MyJobListenerImpl implements JobExecutionListener {
        private MyFileReader reader;
    
    @Override
    public void beforeJob(JobExecution jobExecution) {
        reader.init();
    }
    
    @Override
    public void afterJob(JobExecution jobExecution) {
        // noop
    }
    
    // Injected
    public void setReader(MyFileReader reader) {
        this.reader = reader;
    }
    
  2. 接下来,在您的自定义阅读器中添加一个init方法。

    public void init() {
        if(Files.exists(inputFileLocation)) {
            List<String> inputData = null;
            try {
                inputData = Files.readAllLines(inputFileLocation, StandardCharsets.UTF_8);
            } catch(IOException e) {
                System.out.println("issue reading input file {}. Error message: {}", inputFileLocation, e);
                throw new IllegalStateException("could not read the input file.");
            }
    
            try {
                for(String fileItem : inputData) {
    
                    YourFileDataBean fileData = new YourFileDataBean();
    
                    yourFileDataBean.setField1(fileItem.split(",")[0].trim());
                    yourFileDataBean.setFiled2(fileItem.split(",")[1].trim());
                    yourFileDataBean.setField3(fileItem.split(",")[2].trim());
                    yourFileDataBean.setField4(fileItem.split(",")[3].trim());
                    myDeque.add(yourFileDataBean);  // really up to you how you want to store your bean but you could add a Deque instance variable and store it there.
    
            }
        } catch(ArrayIndexOutOfBoundsException e) {
            LOGGER.warn("ArrayIndexOutOfBoundsException due to data in input file.");
            throw new IllegalStateException("Failure caused by init() method. Error reading in input file.");
        }
    } else {
        LOGGER.warn("Input file {} does not exist.", inputFileLocation);
        throw new IllegalStateException("Input file does not exist at file location " + inputFileLocation);
    }
    }
    
  3. 使自定义阅读器中的read()(或MyFileReader())方法返回由读入的所有文件行填充的对象。在此示例中,我实现了ItemReader而不是像您一样扩展它,但是你明白了。如果您打算返回表示整个文件的单个Java对象,则不需要将对象存储在Deque或List中。

    @Override
    public MyFileReader read() throws NonTransientResourceException {
    
        return myDeque.poll();
    }
    

    希望这会有所帮助。

  4. 将文件地址返回给ItemProcessor。您可以将此字段设置为YourFileDataBean并在其中存储inputFileLocation,或将其保存到执行上下文并以此方式访问它。如果将此文件路径注入到阅读器中,您可以在处理器中执行相同的操作,假设您的阅读器在确定文件路径时没有任何作用(也就是说,它是预定的)。