you can implement StepExecutionListener at itemreader. Then you can get readcount which is corresponds your line number.

 public class ExampleItemReader implements ItemReader<String>, StepExecutionListener {

    public synchronized String read() throws Exception {
        return "";
    }

    @Override
    public ExitStatus afterStep(StepExecution executionContext) {
        if (executionContext.getReadCount() > 8000) {
            return ExitStatus.COMPLETED;
        }
        return ExitStatus.EXECUTING;
    }

    @Override
    public void beforeStep(StepExecution arg0) {

    }

}

advise reading spring batch patterns

Answer from nsylmz on Stack Overflow
Top answer
1 of 2
1

Without seeing you ItemReader config I can't really be sure but if you are using something like FlatFileItemReader to parse a csv, if in strict mode it will validate the number of columns.

Assuming you reader looks like this, that is:

<bean id="iItemReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
    <property name="linesToSkip" value="1"/>
    <property name="comments" value="#" />
    <property name="encoding" value="UTF-8"/>
    <property name="lineMapper" >
        <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
            <property name="lineTokenizer">
                <bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
                    <property name="delimiter" value=","/>
                    <property name="names">
                        <list >
                            <value>First_Field</value>
                        <value>Second_Field</value>
                        </list>
                    </property>
                    <property name="strict" value="true"/>
                </bean>
            </property>
            <property name="fieldSetMapper">
                <bean class="uk.co.package.FieldSetMapper">
                    <property name="dateFormat" value="yyyy-MM-dd HH:mm:ss"/>
                </bean>
            </property>
        </bean>
    </property>

</bean>

It will throw a FlatFileParseException for any lines that can't be processed. This includes the line number and can be handled in a listener.

2 of 2
0

As for the line number, you might build your own LineMapper and then store the line-number in your business object. An example in which I store the line unprocessed (as-is) together with the line number:

    DefaultLineMapper<OneRow> lineMapper = new DefaultLineMapper<OneRow>() {
        @Override
        public OneRow mapLine(String line, int lineNumber) throws Exception {
            return new OneRow(lineNumber, line);
        }
    };

Of course you can already map your Object, I had the need to have the whole line unprocessed as input to my Processors.

As a reference with the same idea: https://stackoverflow.com/a/23770421/5658642

🌐
HowToDoInJava
howtodoinjava.com › home › spring batch › spring batch count of processed records example
Spring Batch Count of Processed Records Example
November 29, 2023 - And I don’t want to log every line. I just want to log only the line number of read or write record that have failed. Do you have any solution ? ... how to read files if one file has corrupted to read remaining files using MultiResourceItemReader in spring boot?
🌐
Stack Overflow
stackoverflow.com › questions › 59955127 › flatfileitemwriterbuilder-headercallback-get-number-of-rows-written
spring - FlatFileItemWriterBuilder-headerCallback() get number of rows written - Stack Overflow
January 29, 2020 - @Bean @StepScope public FlatFileItemWriter<MyFile> generateMyFileWriter(Long jobId,Date eventDate) { String filePath = "C:\MYFILE\COMPLETED"; Resource file = new FileSystemResource(filePath); DelimitedLineAggregator<MyFile> myFileLineAggregator = new DelimitedLineAggregator<>(); myFileLineAggregator.setDelimiter(","); myFileLineAggregator.setFieldExtractor(getMyFileFieldExtractor()); return new FlatFileItemWriterBuilder<MyFile>() .name("my-file-writer") .resource(file) .headerCallback(new MyFileHeaderWriter(file.getFilename())) .lineAggregator(myFileLineAggregator) .build(); } private FieldExtractor<MyFile> getMyFileFieldExtractor() { final String[] fieldNames = new String[]{ "typeRecord", "idSystem" }; return item -> { BeanWrapperFieldExtractor<MyFile> extractor = new BeanWrapperFieldExtractor<>(); extractor.setNames(fieldNames); return extractor.extract(item); }; }
🌐
Google Groups
groups.google.com › g › beanio › c › rnN5Rc7gZl4
Line number in Batch Writer for Spring Batch
October 22, 2013 - Hi Niyant, I'm not sure what you are referring to with "SkipListener" or "BatchWriter". The line number is exposed via beanReader.getLineNumber(). Thanks, Kevin ... Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message ... I was using some terms loosely in my pervious post so things may not have been very clear. I'll make this post more specific by including code snippets. I'm using Spring Batch and so I'm the reading is abstracted into org.beanio.spring.BeanIOFlatFileItemReader:
Top answer
1 of 2
3

I realized that I can get the lineNumber value into MyObject by overriding the DefaultLineMapper with my own LineMapper in this way:

import org.springframework.batch.item.file.FlatFileParseException;
import org.springframework.batch.item.file.LineMapper;
import org.springframework.batch.item.file.transform.LineTokenizer;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import my.model.MyObject;

public class MyLineMapper<T> implements LineMapper<MyObject>, InitializingBean {

    private LineTokenizer tokenizer;

    private ResourceFieldSetMapper fieldSetMapper;

    public MyObject mapLine(String line, int lineNumber) throws Exception {
        try{
            MyObject r = fieldSetMapper.mapFieldSet(tokenizer.tokenize(line));
            // this is the modification
            r.setLineNumber(lineNumber);
            return r;
        }
        catch(Exception ex){
            throw new FlatFileParseException("Parsing error at line: " + lineNumber + 
                    ", input=[" + line + "]", ex, line, lineNumber); 
        }
    }

    public void setLineTokenizer(LineTokenizer tokenizer) {
        this.tokenizer = tokenizer;
    }

    public void setFieldSetMapper(ResourceFieldSetMapper fieldSetMapper) {
        this.fieldSetMapper = fieldSetMapper;
    }

    public void afterPropertiesSet() {
        Assert.notNull(tokenizer, "The LineTokenizer must be set");
        Assert.notNull(fieldSetMapper, "The FieldSetMapper must be set");
    }

}

Thanks for your help! I hope this works for someone!

Blessings!

2 of 2
1

I think you can use spEL expression #{fileReader.currentItemCount}, but there is the SB interface ItemCountAware for this purpose.

Marker interface indicating that an item should have the item count set on it. Typically used within an AbstractItemCountingItemStreamItemReader.

🌐
Stack Overflow
stackoverflow.com › questions › 58718041 › read-specific-lines-from-text-file-using-item-reader-in-spring-batch › 70241543
Read specific lines from text file using Item reader in spring batch - Stack Overflow
You need a custom reader (that could extend FlatFileItemReader) for that. This reader should skip lines until it reads "START-OF-DATA", return every line after that until it reads "END-OF-DATA" where it returns null.
🌐
Stack Overflow
stackoverflow.com › questions › 23740022 › how-to-get-the-number-of-items-read-in-spring-batch-itemreadlistener
java - How to get the number of items read in Spring Batch ItemReadListener - Stack Overflow
May 20, 2014 - In a Spring Batch application, I need to improve my reading error handling for a StaxEventItemReader. ... public class UserAuthorizationErrorListener extends ItemListenerSupport<UserAuthorizationType, UserAuthorizationType> { @Override public void onReadError(Exception ex) { ex.printStackTrace(); //TODO how to get the position in the file ?
Find elsewhere
🌐
Stack Overflow
stackoverflow.com › questions › 63086847 › springbatch-accessing-line-number-in-item-processor
java - SpringBatch accessing Line Number in Item processor - Stack Overflow
July 25, 2020 - Maybe you can check all the annotation available and create a flow that fit your requirements (https://docs.spring.io/spring-batch/docs/current/api/org/springframework/batch/core/annotation/package-summary.html). For example the following processor will init the lineNumber to 0 before the chunk proccess the data. However if the file contains more than the chunk size, you should store the number of chunk that have been executed in the execution context and then add to the lineNumber.
🌐
GitHub
github.com › spring-projects › spring-batch › issues › 1675
add support to access an item's line number [BATCH-1906] · Issue #1675 · spring-projects/spring-batch
November 8, 2012 - Jimmy Praet opened BATCH-1906 and commented Sometimes you want to know the line number of the item that is being processed. It is trivial to add this to the framework, as the line number is currently already being passed to the LineMappe...
Author   spring-projects
Top answer
1 of 3
3

I want to count the number of lines in a file using batch

Specific solution

From a command line:

F:\test>for /f "usebackq" %b in (`type abc.csv ^| find "" /v /c`) do @echo line count is %b
line count is 1

From a batch file (countlines.cmd):

@echo off
Setlocal EnableDelayedExpansion
  for /f "usebackq" %%b in (`type abc.csv ^| find "" /v /c`) do (
    echo line count is %%b
    )
  )

Example:

F:\test>countlines
line count is 1
F:\test>

Flexible solution

Use the following batch file (countlines.cmd):

@echo off
Setlocal EnableDelayedExpansion
for /f "usebackq" %%a in (`dir /b /s %1`)  do (
  echo processing file %%a
  for /f "usebackq" %%b in (`type %%a ^| find "" /v /c`) do (
    echo line count is %%b
    set /a lines += %%b
    )
  )
echo total lines is %lines%

Notes:

  • Total number of lines is stored in %lines%.
  • Batch file supports wildcards.
  • Tweak echo ... commands as appropriate.

Usage:

countlines filename_expression

Example:

F:\test>countlines *.csv
processing file F:\test\abc.csv
line count is 1
processing file F:\test\def.csv
line count is 1
total lines is 2

Further Reading

  • An A-Z Index of the Windows CMD command line - An excellent reference for all things Windows cmd line related.
  • dir - Display a list of files and subfolders.
  • find - Search for a text string in a file & display all the lines where it is found.
  • for /f - Loop command against the results of another command.
2 of 3
2

A simple way to count the number of lines in a file on a Microsoft Windows system is by using the following command:

find /v /c "" somefile.txt

The /c option counts the number of lines while the /v option displays all lines NOT containing the specified string. Since the null string, i.e. "", is treated as never matching, you should see the number of lines in the file displayed - see the Stupid command-line trick: Counting the number of lines in stdin article at Raymond Chen's Microsoft Developer Blog, The Old New Thing for an explanation of why this works and how a bug in the earliest MS-DOS version of the find command became a feature that remains to this day. The MS-DOS operating system was an operating system for early PCs provided by Microsoft long before the company created Microsoft Windows.

🌐
Spring
docs.spring.io › spring-batch › reference › readers-and-writers › flat-files › file-item-reader.html
FlatFileItemReader :: Spring Batch Reference
Reading flat files in the Spring Batch framework is facilitated by the class called FlatFileItemReader, which provides basic functionality for reading and parsing flat files. The two most important required dependencies of FlatFileItemReader are Resource and LineMapper.
🌐
Mkyong
mkyong.com › home › java › java – count number of lines in a file
Java - Count number of lines in a file - Mkyong.com
July 21, 2020 - It gives an error “The Line number is beyond the total number of lines” and shows up the the immediately available line. If you have 2379 lines it gives 2380. So whatever it shows up minus 1 is the actual number of lines in the text file. Cheers!! ... Mkyong.com has provided Java and Spring tutorials, guides, and code snippets since 2008.
🌐
Spring
docs.spring.io › spring-batch › docs › 1.0.x › spring-batch-docs › reference › html › spring-batch-infrastructure.html
Chapter 3. ItemReaders and ItemWriters
Reading flat files in the Spring Batch framework is facilitated by the class FlatFileItemReader, which provides basic functionality for reading and parsing flat files. FlatFileItemReader class has several properties. The three most important of these properties are Resource, FieldSetMapper and LineTokenizer.
🌐
Desynit
desynit.com › dev-zone › java › spring-batch-log-the-record-count-during-processing
Spring Batch - Log the record count during processing - Desynit
December 12, 2018 - The class uses the count of items read, rather than the items written, as you may have a processor that filters out some of the records – in which case the number of items written will not increase in a consistent manner. If you’re configuring your Spring app using XML, then you add a bean like this:
🌐
Craftsmen
craftsmen.nl › home › processing files with fixed line length using spring batch
Processing files with fixed line length using Spring Batch - Craftsmen
July 17, 2022 - For this we can use Spring Batch Event Listeners, and in this particular case a SkipListener where we can implement some logic in case the step failed in the read, process or write part. Besides logging we can also choose to write the line that failed to be processed to a database. When an error occurs in the reading part of the step this can result in a FlatFileParseException. In this case we can get hold of the line that was read and log it along with the exception.
Top answer
1 of 4
2

Using the JobExplorer, you can look at the previous StepExecutions to get the number of items read, etc in each step. You can read more about the JobExplorer here: http://docs.spring.io/spring-batch/trunk/apidocs/org/springframework/batch/core/explore/JobExplorer.html

Update

You actually don't even need to use the JobExplorer. Since you have the JobExecution, you already have references to all the StepExecutions. Each StepExecution contains the number of items read, processed, written, skipped, etc.

2 of 4
1

I see 2 ways to do it.

  1. You can implement the ItemProcessListener. This interface is called after/before an item is processed. This interface also reported any errors.

    public class ItemCountsListener implements ItemProcessListener<Object, Object> {
    
    private static final AtomicLong count = new AtomicLong(1);
    
    public void afterProcess(Object item, Object result) {
        count.getAndIncrement();
    }
    
    public void beforeProcess(Object item) {}
    public void onProcessError(Object item, Exception e) {  }
    

    }

  2. Or you can call the method jobExecution.getStepExecutions(). This method returns a Collection<StepExecution> object. In this class, there is a method getWriteCount which returns the current number of items written for this execution. I would do something similar to this code :

 public void afterJob(JobExecution jobExecution) {
         int nbItemsProcessed;
         for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
            nbItemsProcessed += stepExecution.getWriteCount();
         }   
      }