@@ -155,6 +155,7 @@ public static class Builder extends AbstractStreamBuilder<CSVParser, Builder> {
155155 private CSVFormat format ;
156156 private long characterOffset ;
157157 private long recordNumber = 1 ;
158+ private boolean enableByteTracking ;
158159
159160 /**
160161 * Constructs a new instance.
@@ -166,7 +167,7 @@ protected Builder() {
166167 @ SuppressWarnings ("resource" )
167168 @ Override
168169 public CSVParser get () throws IOException {
169- return new CSVParser (getReader (), format != null ? format : CSVFormat .DEFAULT , characterOffset , recordNumber );
170+ return new CSVParser (getReader (), format != null ? format : CSVFormat .DEFAULT , characterOffset , recordNumber , getCharset (), enableByteTracking );
170171 }
171172
172173 /**
@@ -202,6 +203,18 @@ public Builder setRecordNumber(final long recordNumber) {
202203 return asThis ();
203204 }
204205
206+ /**
207+ * Sets whether to enable byte tracking for the parser.
208+ *
209+ * @param enableByteTracking {@code true} to enable byte tracking; {@code false} to disable it.
210+ * @return this instance.
211+ * @since 1.13.0
212+ */
213+ public Builder setEnableByteTracking (final boolean enableByteTracking ) {
214+ this .enableByteTracking = enableByteTracking ;
215+ return asThis ();
216+ }
217+
205218 }
206219
207220 final class CSVRecordIterator implements Iterator <CSVRecord > {
@@ -510,11 +523,43 @@ public CSVParser(final Reader reader, final CSVFormat format) throws IOException
510523 @ Deprecated
511524 @ SuppressWarnings ("resource" )
512525 public CSVParser (final Reader reader , final CSVFormat format , final long characterOffset , final long recordNumber )
526+ throws IOException {
527+ this (reader , format , characterOffset , recordNumber , null , false );
528+ }
529+
530+ /**
531+ * Constructs a new instance using the given {@link CSVFormat}
532+ *
533+ * <p>
534+ * If you do not read all records from the given {@code reader}, you should call {@link #close()} on the parser,
535+ * unless you close the {@code reader}.
536+ * </p>
537+ *
538+ * @param reader
539+ * a Reader containing CSV-formatted input. Must not be null.
540+ * @param format
541+ * the CSVFormat used for CSV parsing. Must not be null.
542+ * @param characterOffset
543+ * Lexer offset when the parser does not start parsing at the beginning of the source.
544+ * @param recordNumber
545+ * The next record number to assign.
546+ * @param charset
547+ * The character encoding to be used for the reader when enableByteTracking is true.
548+ * @param enableByteTracking
549+ * {@code true} to enable byte tracking for the parser; {@code false} to disable it.
550+ * @throws IllegalArgumentException
551+ * If the parameters of the format are inconsistent or if either the reader or format is null.
552+ * @throws IOException
553+ * If there is a problem reading the header or skipping the first record.
554+ * @throws CSVException Thrown on invalid input.
555+ */
556+ private CSVParser (final Reader reader , final CSVFormat format , final long characterOffset , final long recordNumber ,
557+ final Charset charset , final boolean enableByteTracking )
513558 throws IOException {
514559 Objects .requireNonNull (reader , "reader" );
515560 Objects .requireNonNull (format , "format" );
516561 this .format = format .copy ();
517- this .lexer = new Lexer (format , new ExtendedBufferedReader (reader ));
562+ this .lexer = new Lexer (format , new ExtendedBufferedReader (reader , charset , enableByteTracking ));
518563 this .csvRecordIterator = new CSVRecordIterator ();
519564 this .headers = createHeaders ();
520565 this .characterOffset = characterOffset ;
@@ -841,6 +886,7 @@ CSVRecord nextRecord() throws IOException {
841886 recordList .clear ();
842887 StringBuilder sb = null ;
843888 final long startCharPosition = lexer .getCharacterPosition () + characterOffset ;
889+ final long startBytePosition = lexer .getBytesRead () + this .characterOffset ;
844890 do {
845891 reusableToken .reset ();
846892 lexer .nextToken (reusableToken );
@@ -878,7 +924,7 @@ CSVRecord nextRecord() throws IOException {
878924 recordNumber ++;
879925 final String comment = Objects .toString (sb , null );
880926 result = new CSVRecord (this , recordList .toArray (Constants .EMPTY_STRING_ARRAY ), comment ,
881- recordNumber , startCharPosition );
927+ recordNumber , startCharPosition , startBytePosition );
882928 }
883929 return result ;
884930 }
0 commit comments