001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020package org.apache.commons.csv;
021
022import static org.apache.commons.io.IOUtils.EOF;
023
024import java.io.File;
025import java.io.IOException;
026import java.io.InputStream;
027import java.io.OutputStream;
028import java.io.Reader;
029import java.io.Serializable;
030import java.io.StringWriter;
031import java.io.Writer;
032import java.nio.charset.Charset;
033import java.nio.file.Files;
034import java.nio.file.Path;
035import java.sql.ResultSet;
036import java.sql.ResultSetMetaData;
037import java.sql.SQLException;
038import java.util.Arrays;
039import java.util.HashSet;
040import java.util.Objects;
041import java.util.Set;
042import java.util.function.Supplier;
043
044import org.apache.commons.codec.binary.Base64OutputStream;
045import org.apache.commons.io.IOUtils;
046import org.apache.commons.io.function.IOStream;
047import org.apache.commons.io.function.Uncheck;
048import org.apache.commons.io.output.AppendableOutputStream;
049
050/**
051 * Specifies the format of a CSV file for parsing and writing.
052 *
053 * <h2>Using predefined formats</h2>
054 *
055 * <p>
056 * You can use one of the predefined formats:
057 * </p>
058 *
059 * <ul>
060 * <li>{@link #DEFAULT}</li>
061 * <li>{@link #EXCEL}</li>
062 * <li>{@link #INFORMIX_UNLOAD}</li>
063 * <li>{@link #INFORMIX_UNLOAD_CSV}</li>
064 * <li>{@link #MONGODB_CSV}</li>
065 * <li>{@link #MONGODB_TSV}</li>
066 * <li>{@link #MYSQL}</li>
067 * <li>{@link #ORACLE}</li>
068 * <li>{@link #POSTGRESQL_CSV}</li>
069 * <li>{@link #POSTGRESQL_TEXT}</li>
070 * <li>{@link #RFC4180}</li>
071 * <li>{@link #TDF}</li>
072 * </ul>
073 *
074 * <p>
075 * For example:
076 * </p>
077 *
078 * <pre>
079 * CSVParser parser = CSVFormat.EXCEL.parse(reader);
080 * </pre>
081 *
082 * <p>
083 * The {@link CSVParser} provides static methods to parse other input types, for example:
084 * </p>
085 *
086 * <pre>
087 * CSVParser parser = CSVParser.parse(file, StandardCharsets.US_ASCII, CSVFormat.EXCEL);
088 * </pre>
089 *
090 * <h2>Defining formats</h2>
091 *
092 * <p>
093 * You can extend a format by calling the {@code set} methods. For example:
094 * </p>
095 *
096 * <pre>{@code
097 * CSVFormat.EXCEL.builder().setNullString("N/A").setIgnoreSurroundingSpaces(true).get();
098 * }</pre>
099 *
100 * <h2>Defining column names</h2>
101 *
102 * <p>
103 * To define the column names you want to use to access records, write:
104 * </p>
105 *
106 * <pre>{@code
107 * CSVFormat.EXCEL.builder().setHeader("Col1", "Col2", "Col3").get();
108 * }</pre>
109 *
110 * <p>
111 * Calling {@link Builder#setHeader(String...)} lets you use the given names to address values in a {@link CSVRecord}, and assumes that your CSV source does not
112 * contain a first record that also defines column names.
113 *
114 * If it does, then you are overriding this metadata with your names and you should skip the first record by calling
115 * {@link Builder#setSkipHeaderRecord(boolean)} with {@code true}.
116 * </p>
117 *
118 * <h2>Parsing</h2>
119 *
120 * <p>
121 * You can use a format directly to parse a reader. For example, to parse an Excel file with columns header, write:
122 * </p>
123 *
124 * <pre>{@code
125 * Reader in = ...;
126 * CSVFormat.EXCEL.builder().setHeader("Col1", "Col2", "Col3").get().parse(in);
127 * }</pre>
128 *
129 * <p>
130 * For other input types, like resources, files, and URLs, use the static methods on {@link CSVParser}.
131 * </p>
132 *
133 * <h2>Referencing columns safely</h2>
134 *
135 * <p>
136 * If your source contains a header record, you can simplify your code and safely reference columns, by using {@link Builder#setHeader(String...)} with no
137 * arguments:
138 * </p>
139 *
140 * <pre>
141 * CSVFormat.EXCEL.builder().setHeader().get();
142 * </pre>
143 *
144 * <p>
145 * This causes the parser to read the first record and use its values as column names.
146 *
147 * Then, call one of the {@link CSVRecord} get method that takes a String column name argument:
148 * </p>
149 *
150 * <pre>{@code
151 * String value = record.get("Col1");
152 * }</pre>
153 *
154 * <p>
155 * This makes your code impervious to changes in column order in the CSV file.
156 * </p>
157 *
158 * <h2>Serialization</h2>
159 * <p>
160 * This class implements the {@link Serializable} interface with the following caveats:
161 * </p>
162 * <ul>
163 * <li>This class will no longer implement Serializable in 2.0.</li>
164 * <li>Serialization is not supported from one version to the next.</li>
165 * </ul>
166 * <p>
167 * The {@code serialVersionUID} values are:
168 * </p>
169 * <ul>
170 * <li>Version 1.10.0: {@code 2L}</li>
171 * <li>Version 1.9.0 through 1.0: {@code 1L}</li>
172 * </ul>
173 *
174 * <h2>Notes</h2>
175 * <p>
176 * This class is immutable.
177 * </p>
178 * <p>
179 * Not all settings are used for both parsing and writing.
180 * </p>
181 */
182public final class CSVFormat implements Serializable {
183
184    /**
185     * Builds CSVFormat instances.
186     *
187     * @since 1.9.0
188     */
189    public static class Builder implements Supplier<CSVFormat> {
190
191        /**
192         * Creates a new default builder, as for {@link #RFC4180} but allowing empty lines.
193         *
194         * <p>
195         * The {@link Builder} settings are:
196         * </p>
197         * <ul>
198         * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')}</li>
199         * <li>{@link Builder#setQuote(char) setQuote}{@code ('"')}</li>
200         * <li>{@link Builder#setRecordSeparator(String) setRecordSeparator}{@code ("\r\n")}</li>
201         * <li>{@link Builder#setIgnoreEmptyLines(boolean) setIgnoreEmptyLines}{@code (true)}</li>
202         * <li>{@link Builder#setDuplicateHeaderMode(DuplicateHeaderMode) setDuplicateHeaderMode}{@code (DuplicateHeaderMode.ALLOW_ALL)}</li>
203         * <li>All other values take their Java defaults, {@code false} for booleans, {@code null} for object references.</li>
204         * </ul>
205         *
206         * @see Predefined#Default
207         * @see DuplicateHeaderMode#ALLOW_ALL
208         *
209         * @return a copy of the builder
210         */
211        public static Builder create() {
212            // @formatter:off
213            return new Builder()
214                    .setDelimiter(Constants.COMMA)
215                    .setQuote(Constants.DOUBLE_QUOTE_CHAR)
216                    .setRecordSeparator(Constants.CRLF)
217                    .setIgnoreEmptyLines(true)
218                    .setDuplicateHeaderMode(DuplicateHeaderMode.ALLOW_ALL);
219                    // @formatter:on
220        }
221
222        /**
223         * Creates a new builder from the given format.
224         *
225         * @param csvFormat the source format.
226         * @return a new builder.
227         */
228        public static Builder create(final CSVFormat csvFormat) {
229            return new Builder(csvFormat);
230        }
231
232        private boolean allowMissingColumnNames;
233
234        private boolean autoFlush;
235
236        private Character commentMarker;
237
238        private String delimiter;
239
240        private DuplicateHeaderMode duplicateHeaderMode;
241
242        private Character escapeCharacter;
243
244        private String[] headerComments;
245
246        private String[] headers;
247
248        private boolean ignoreEmptyLines;
249
250        private boolean ignoreHeaderCase;
251
252        private boolean ignoreSurroundingSpaces;
253
254        private String nullString;
255
256        private Character quoteCharacter;
257
258        private String quotedNullString;
259
260        private QuoteMode quoteMode;
261
262        private String recordSeparator;
263
264        private boolean skipHeaderRecord;
265
266        private boolean lenientEof;
267
268        private boolean trailingData;
269
270        private boolean trailingDelimiter;
271
272        private boolean trim;
273
274        /** The maximum number of rows to process, excluding the header row. */
275        private long maxRows;
276
277        private Builder() {
278            // empty
279        }
280
281        private Builder(final CSVFormat csvFormat) {
282            this.allowMissingColumnNames = csvFormat.allowMissingColumnNames;
283            this.autoFlush = csvFormat.autoFlush;
284            this.commentMarker = csvFormat.commentMarker;
285            this.delimiter = csvFormat.delimiter;
286            this.duplicateHeaderMode = csvFormat.duplicateHeaderMode;
287            this.escapeCharacter = csvFormat.escapeCharacter;
288            this.headerComments = csvFormat.headerComments;
289            this.headers = csvFormat.headers;
290            this.ignoreEmptyLines = csvFormat.ignoreEmptyLines;
291            this.ignoreHeaderCase = csvFormat.ignoreHeaderCase;
292            this.ignoreSurroundingSpaces = csvFormat.ignoreSurroundingSpaces;
293            this.lenientEof = csvFormat.lenientEof;
294            this.maxRows = csvFormat.maxRows;
295            this.nullString = csvFormat.nullString;
296            this.quoteCharacter = csvFormat.quoteCharacter;
297            this.quoteMode = csvFormat.quoteMode;
298            this.quotedNullString = csvFormat.quotedNullString;
299            this.recordSeparator = csvFormat.recordSeparator;
300            this.skipHeaderRecord = csvFormat.skipHeaderRecord;
301            this.trailingData = csvFormat.trailingData;
302            this.trailingDelimiter = csvFormat.trailingDelimiter;
303            this.trim = csvFormat.trim;
304        }
305
306        /**
307         * Builds a new CSVFormat instance.
308         *
309         * @return a new CSVFormat instance.
310         * @deprecated Use {@link #get()}.
311         */
312        @Deprecated
313        public CSVFormat build() {
314            return get();
315        }
316
317        /**
318         * Builds a new CSVFormat instance.
319         *
320         * @return a new CSVFormat instance.
321         * @since 1.13.0
322         */
323        @Override
324        public CSVFormat get() {
325            return new CSVFormat(this);
326        }
327
328        /**
329         * Sets the duplicate header names behavior, true to allow, false to disallow.
330         *
331         * @param allowDuplicateHeaderNames the duplicate header names behavior, true to allow, false to disallow.
332         * @return This instance.
333         * @deprecated Use {@link #setDuplicateHeaderMode(DuplicateHeaderMode)}.
334         */
335        @Deprecated
336        public Builder setAllowDuplicateHeaderNames(final boolean allowDuplicateHeaderNames) {
337            setDuplicateHeaderMode(allowDuplicateHeaderNames ? DuplicateHeaderMode.ALLOW_ALL : DuplicateHeaderMode.ALLOW_EMPTY);
338            return this;
339        }
340
341        /**
342         * Sets the parser missing column names behavior, {@code true} to allow missing column names in the header line, {@code false} to cause an
343         * {@link IllegalArgumentException} to be thrown.
344         *
345         * @param allowMissingColumnNames the missing column names behavior, {@code true} to allow missing column names in the header line, {@code false} to
346         *                                cause an {@link IllegalArgumentException} to be thrown.
347         * @return This instance.
348         */
349        public Builder setAllowMissingColumnNames(final boolean allowMissingColumnNames) {
350            this.allowMissingColumnNames = allowMissingColumnNames;
351            return this;
352        }
353
354        /**
355         * Sets whether to flush on close.
356         *
357         * @param autoFlush whether to flush on close.
358         * @return This instance.
359         */
360        public Builder setAutoFlush(final boolean autoFlush) {
361            this.autoFlush = autoFlush;
362            return this;
363        }
364
365        /**
366         * Sets the comment marker character, use {@code null} to disable comments.
367         * <p>
368         * The comment start character is only recognized at the start of a line.
369         * </p>
370         * <p>
371         * Comments are printed first, before headers.
372         * </p>
373         * <p>
374         * Use {@link #setCommentMarker(char)} or {@link #setCommentMarker(Character)} to set the comment marker written at the start of each comment line.
375         * </p>
376         * <p>
377         * If the comment marker is not set, then the header comments are ignored.
378         * </p>
379         * <p>
380         * For example:
381         * </p>
382         *
383         * <pre>
384         * builder.setCommentMarker('#').setHeaderComments("Generated by Apache Commons CSV", Instant.ofEpochMilli(0));
385         * </pre>
386         * <p>
387         * writes:
388         * </p>
389         *
390         * <pre>
391         * # Generated by Apache Commons CSV.
392         * # 1970-01-01T00:00:00Z
393         * </pre>
394         *
395         * @param commentMarker the comment start marker, use {@code null} to disable.
396         * @return This instance.
397         * @throws IllegalArgumentException thrown if the specified character is a line break
398         */
399        public Builder setCommentMarker(final char commentMarker) {
400            setCommentMarker(Character.valueOf(commentMarker));
401            return this;
402        }
403
404        /**
405         * Sets the comment marker character, use {@code null} to disable comments.
406         * <p>
407         * The comment start character is only recognized at the start of a line.
408         * </p>
409         * <p>
410         * Comments are printed first, before headers.
411         * </p>
412         * <p>
413         * Use {@link #setCommentMarker(char)} or {@link #setCommentMarker(Character)} to set the comment marker written at the start of each comment line.
414         * </p>
415         * <p>
416         * If the comment marker is not set, then the header comments are ignored.
417         * </p>
418         * <p>
419         * For example:
420         * </p>
421         *
422         * <pre>
423         * builder.setCommentMarker('#').setHeaderComments("Generated by Apache Commons CSV", Instant.ofEpochMilli(0));
424         * </pre>
425         * <p>
426         * writes:
427         * </p>
428         *
429         * <pre>
430         * # Generated by Apache Commons CSV.
431         * # 1970-01-01T00:00:00Z
432         * </pre>
433         *
434         * @param commentMarker the comment start marker, use {@code null} to disable.
435         * @return This instance.
436         * @throws IllegalArgumentException thrown if the specified character is a line break
437         */
438        public Builder setCommentMarker(final Character commentMarker) {
439            if (isLineBreak(commentMarker)) {
440                throw new IllegalArgumentException("The comment start marker character cannot be a line break");
441            }
442            this.commentMarker = commentMarker;
443            return this;
444        }
445
446        /**
447         * Sets the delimiter character.
448         *
449         * @param delimiter the delimiter character.
450         * @return This instance.
451         */
452        public Builder setDelimiter(final char delimiter) {
453            return setDelimiter(String.valueOf(delimiter));
454        }
455
456        /**
457         * Sets the delimiter character.
458         *
459         * @param delimiter the delimiter character.
460         * @return This instance.
461         */
462        public Builder setDelimiter(final String delimiter) {
463            if (containsLineBreak(delimiter)) {
464                throw new IllegalArgumentException("The delimiter cannot be a line break");
465            }
466            if (delimiter.isEmpty()) {
467                throw new IllegalArgumentException("The delimiter cannot be empty");
468            }
469            this.delimiter = delimiter;
470            return this;
471        }
472
473        /**
474         * Sets the duplicate header names behavior.
475         *
476         * @param duplicateHeaderMode the duplicate header names behavior
477         * @return This instance.
478         * @since 1.10.0
479         */
480        public Builder setDuplicateHeaderMode(final DuplicateHeaderMode duplicateHeaderMode) {
481            this.duplicateHeaderMode = Objects.requireNonNull(duplicateHeaderMode, "duplicateHeaderMode");
482            return this;
483        }
484
485        /**
486         * Sets the escape character.
487         *
488         * @param escapeCharacter the escape character.
489         * @return This instance.
490         * @throws IllegalArgumentException thrown if the specified character is a line break
491         */
492        public Builder setEscape(final char escapeCharacter) {
493            setEscape(Character.valueOf(escapeCharacter));
494            return this;
495        }
496
497        /**
498         * Sets the escape character.
499         *
500         * @param escapeCharacter the escape character.
501         * @return This instance.
502         * @throws IllegalArgumentException thrown if the specified character is a line break
503         */
504        public Builder setEscape(final Character escapeCharacter) {
505            if (isLineBreak(escapeCharacter)) {
506                throw new IllegalArgumentException("The escape character cannot be a line break");
507            }
508            this.escapeCharacter = escapeCharacter;
509            return this;
510        }
511
512        /**
513         * Sets the header defined by the given {@link Enum} class.
514         *
515         * <p>
516         * Example:
517         * </p>
518         *
519         * <pre>
520         * public enum HeaderEnum {
521         *     Name, Email, Phone
522         * }
523         *
524         * Builder builder = builder.setHeader(HeaderEnum.class);
525         * </pre>
526         * <p>
527         * The header is also used by the {@link CSVPrinter}.
528         * </p>
529         *
530         * @param headerEnum the enum defining the header, {@code null} if disabled, empty if parsed automatically, user-specified otherwise.
531         * @return This instance.
532         */
533        public Builder setHeader(final Class<? extends Enum<?>> headerEnum) {
534            String[] header = null;
535            if (headerEnum != null) {
536                final Enum<?>[] enumValues = headerEnum.getEnumConstants();
537                header = new String[enumValues.length];
538                Arrays.setAll(header, i -> enumValues[i].name());
539            }
540            return setHeader(header);
541        }
542
543        /**
544         * Sets the header from the result set metadata. The header can be parsed automatically from the input file with:
545         *
546         * <pre>
547         * builder.setHeader();
548         * </pre>
549         *
550         * or specified manually with:
551         *
552         * <pre>
553         * builder.setHeader(resultSet);
554         * </pre>
555         * <p>
556         * The header is also used by the {@link CSVPrinter}.
557         * </p>
558         *
559         * @param resultSet the resultSet for the header, {@code null} if disabled, empty if parsed automatically, user-specified otherwise.
560         * @return This instance.
561         * @throws SQLException SQLException if a database access error occurs or this method is called on a closed result set.
562         */
563        public Builder setHeader(final ResultSet resultSet) throws SQLException {
564            return setHeader(resultSet != null ? resultSet.getMetaData() : null);
565        }
566
567        /**
568         * Sets the header from the result set metadata. The header can be parsed automatically from the input file with:
569         *
570         * <pre>
571         * builder.setHeader();
572         * </pre>
573         *
574         * or specified manually with:
575         *
576         * <pre>
577         * builder.setHeader(resultSetMetaData);
578         * </pre>
579         * <p>
580         * The header is also used by the {@link CSVPrinter}.
581         * </p>
582         *
583         * @param resultSetMetaData the metaData for the header, {@code null} if disabled, empty if parsed automatically, user-specified otherwise.
584         * @return This instance.
585         * @throws SQLException SQLException if a database access error occurs or this method is called on a closed result set.
586         */
587        public Builder setHeader(final ResultSetMetaData resultSetMetaData) throws SQLException {
588            String[] labels = null;
589            if (resultSetMetaData != null) {
590                final int columnCount = resultSetMetaData.getColumnCount();
591                labels = new String[columnCount];
592                for (int i = 0; i < columnCount; i++) {
593                    labels[i] = resultSetMetaData.getColumnLabel(i + 1);
594                }
595            }
596            return setHeader(labels);
597        }
598
599        /**
600         * Sets the header to the given values. The header can be parsed automatically from the input file with:
601         *
602         * <pre>
603         * builder.setHeader();
604         * </pre>
605         *
606         * or specified manually with:
607         *
608         * <pre>{@code
609         * builder.setHeader("name", "email", "phone");
610         * }</pre>
611         * <p>
612         * The header is also used by the {@link CSVPrinter}.
613         * </p>
614         * <p>
615         * This method keeps a copy of the input array.
616         * </p>
617         * @param header the header, {@code null} if disabled, empty if parsed automatically, user-specified otherwise.
618         * @return This instance.
619         */
620        public Builder setHeader(final String... header) {
621            this.headers = CSVFormat.clone(header);
622            return this;
623        }
624
625        /**
626         * Sets the header comments to write before the CSV data.
627         * <p>
628         * This setting is ignored by the parser.
629         * </p>
630         * <p>
631         * Comments are printed first, before headers.
632         * </p>
633         * <p>
634         * Use {@link #setCommentMarker(char)} or {@link #setCommentMarker(Character)} to set the comment marker written at the start of each comment line.
635         * </p>
636         * <p>
637         * If the comment marker is not set, then the header comments are ignored.
638         * </p>
639         * <p>
640         * For example:
641         * </p>
642         *
643         * <pre>
644         * builder.setCommentMarker('#').setHeaderComments("Generated by Apache Commons CSV", Instant.ofEpochMilli(0));
645         * </pre>
646         * <p>
647         * writes:
648         * </p>
649         *
650         * <pre>
651         * # Generated by Apache Commons CSV.
652         * # 1970-01-01T00:00:00Z
653         * </pre>
654         * <p>
655         * This method keeps a copy of the input array.
656         * </p>
657         *
658         * @param headerComments the headerComments which will be printed by the Printer before the CSV data.
659         * @return This instance.
660         */
661        public Builder setHeaderComments(final Object... headerComments) {
662            this.headerComments = CSVFormat.clone(toStringArray(headerComments));
663            return this;
664        }
665
666        /**
667         * Sets the header comments to write before the CSV data.
668         * <p>
669         * This setting is ignored by the parser.
670         * </p>
671         * <p>
672         * Comments are printed first, before headers.
673         * </p>
674         * <p>
675         * Use {@link #setCommentMarker(char)} or {@link #setCommentMarker(Character)} to set the comment marker written at the start of each comment line.
676         * </p>
677         * <p>
678         * If the comment marker is not set, then the header comments are ignored.
679         * </p>
680         * <p>
681         * For example:
682         * </p>
683         *
684         * <pre>
685         * builder.setCommentMarker('#').setHeaderComments("Generated by Apache Commons CSV", Instant.ofEpochMilli(0).toString());
686         * </pre>
687         * <p>
688         * writes:
689         * </p>
690         *
691         * <pre>
692         * # Generated by Apache Commons CSV.
693         * # 1970-01-01T00:00:00Z
694         * </pre>
695         * <p>
696         * This method keeps a copy of the input array.
697         * </p>
698         * @param headerComments the headerComments which will be printed by the Printer before the CSV data.
699         * @return This instance.
700         */
701        public Builder setHeaderComments(final String... headerComments) {
702            this.headerComments = CSVFormat.clone(headerComments);
703            return this;
704        }
705
706        /**
707         * Sets the empty line skipping behavior, {@code true} to ignore the empty lines between the records, {@code false} to translate empty lines to empty
708         * records.
709         *
710         * @param ignoreEmptyLines the empty line skipping behavior, {@code true} to ignore the empty lines between the records, {@code false} to translate
711         *                         empty lines to empty records.
712         * @return This instance.
713         */
714        public Builder setIgnoreEmptyLines(final boolean ignoreEmptyLines) {
715            this.ignoreEmptyLines = ignoreEmptyLines;
716            return this;
717        }
718
719        /**
720         * Sets the parser case mapping behavior, {@code true} to access name/values, {@code false} to leave the mapping as is.
721         *
722         * @param ignoreHeaderCase the case mapping behavior, {@code true} to access name/values, {@code false} to leave the mapping as is.
723         * @return This instance.
724         */
725        public Builder setIgnoreHeaderCase(final boolean ignoreHeaderCase) {
726            this.ignoreHeaderCase = ignoreHeaderCase;
727            return this;
728        }
729
730        /**
731         * Sets the parser trimming behavior, {@code true} to remove the surrounding spaces, {@code false} to leave the spaces as is.
732         *
733         * @param ignoreSurroundingSpaces the parser trimming behavior, {@code true} to remove the surrounding spaces, {@code false} to leave the spaces as is.
734         * @return This instance.
735         */
736        public Builder setIgnoreSurroundingSpaces(final boolean ignoreSurroundingSpaces) {
737            this.ignoreSurroundingSpaces = ignoreSurroundingSpaces;
738            return this;
739        }
740
741        /**
742         * Sets whether reading end-of-file is allowed even when input is malformed, helps Excel compatibility.
743         *
744         * @param lenientEof whether reading end-of-file is allowed even when input is malformed, helps Excel compatibility.
745         * @return This instance.
746         * @since 1.11.0
747         */
748        public Builder setLenientEof(final boolean lenientEof) {
749            this.lenientEof = lenientEof;
750            return this;
751        }
752
753        /**
754         * Sets the maximum number of rows to process, excluding the header row.
755         * <p>
756         * Values less than or equal to 0 mean no limit.
757         * </p>
758         *
759         * @param maxRows the maximum number of rows to process, excluding the header row.
760         * @return This instance.
761         * @since 1.14.0
762         */
763        public Builder setMaxRows(final long maxRows) {
764            this.maxRows = maxRows;
765            return this;
766        }
767
768        /**
769         * Sets the String to convert to and from {@code null}. No substitution occurs if {@code null}.
770         *
771         * <ul>
772         * <li><strong>Reading:</strong> Converts strings equal to the given {@code nullString} to {@code null} when reading records.</li>
773         * <li><strong>Writing:</strong> Writes {@code null} as the given {@code nullString} when writing records.</li>
774         * </ul>
775         *
776         * @param nullString the String to convert to and from {@code null}. No substitution occurs if {@code null}.
777         * @return This instance.
778         */
779        public Builder setNullString(final String nullString) {
780            this.nullString = nullString;
781            this.quotedNullString = quoteCharacter + nullString + quoteCharacter;
782            return this;
783        }
784
785        /**
786         * Sets the quote character.
787         *
788         * @param quoteCharacter the quote character.
789         * @return This instance.
790         */
791        public Builder setQuote(final char quoteCharacter) {
792            setQuote(Character.valueOf(quoteCharacter));
793            return this;
794        }
795
796        /**
797         * Sets the quote character, use {@code null} to disable.
798         *
799         * @param quoteCharacter the quote character, use {@code null} to disable.
800         * @return This instance.
801         */
802        public Builder setQuote(final Character quoteCharacter) {
803            if (isLineBreak(quoteCharacter)) {
804                throw new IllegalArgumentException("The quoteCharacter cannot be a line break");
805            }
806            this.quoteCharacter = quoteCharacter;
807            return this;
808        }
809
810        /**
811         * Sets the quote policy to use for output.
812         *
813         * @param quoteMode the quote policy to use for output.
814         * @return This instance.
815         */
816        public Builder setQuoteMode(final QuoteMode quoteMode) {
817            this.quoteMode = quoteMode;
818            return this;
819        }
820
821        /**
822         * Sets the record separator to use for output.
823         *
824         * <p>
825         * <strong>Note:</strong> This setting is only used during printing and does not affect parsing. Parsing currently only works for inputs with '\n', '\r'
826         * and "\r\n"
827         * </p>
828         *
829         * @param recordSeparator the record separator to use for output.
830         * @return This instance.
831         */
832        public Builder setRecordSeparator(final char recordSeparator) {
833            this.recordSeparator = String.valueOf(recordSeparator);
834            return this;
835        }
836
837        /**
838         * Sets the record separator to use for output.
839         *
840         * <p>
841         * <strong>Note:</strong> This setting is only used during printing and does not affect parsing. Parsing currently only works for inputs with '\n', '\r'
842         * and "\r\n"
843         * </p>
844         *
845         * @param recordSeparator the record separator to use for output.
846         * @return This instance.
847         */
848        public Builder setRecordSeparator(final String recordSeparator) {
849            this.recordSeparator = recordSeparator;
850            return this;
851        }
852
853        /**
854         * Sets whether to skip the header record.
855         *
856         * @param skipHeaderRecord whether to skip the header record.
857         * @return This instance.
858         */
859        public Builder setSkipHeaderRecord(final boolean skipHeaderRecord) {
860            this.skipHeaderRecord = skipHeaderRecord;
861            return this;
862        }
863
864        /**
865         * Sets whether reading trailing data is allowed in records, helps Excel compatibility.
866         *
867         * @param trailingData whether reading trailing data is allowed in records, helps Excel compatibility.
868         * @return This instance.
869         * @since 1.11.0
870         */
871        public Builder setTrailingData(final boolean trailingData) {
872            this.trailingData = trailingData;
873            return this;
874        }
875
876        /**
877         * Sets whether to add a trailing delimiter.
878         *
879         * @param trailingDelimiter whether to add a trailing delimiter.
880         * @return This instance.
881         */
882        public Builder setTrailingDelimiter(final boolean trailingDelimiter) {
883            this.trailingDelimiter = trailingDelimiter;
884            return this;
885        }
886
887
888        /**
889         * Sets whether to trim leading and trailing blanks.
890         *
891         * @param trim whether to trim leading and trailing blanks.
892         * @return This instance.
893         */
894        public Builder setTrim(final boolean trim) {
895            this.trim = trim;
896            return this;
897        }
898    }
899
900    /**
901     * Predefines formats.
902     *
903     * @since 1.2
904     */
905    public enum Predefined {
906
907        /**
908         * The DEFAULT predefined format.
909         *
910         * @see CSVFormat#DEFAULT
911         */
912        Default(DEFAULT),
913
914        /**
915         * The EXCEL predefined format.
916         *
917         * @see CSVFormat#EXCEL
918         */
919        Excel(EXCEL),
920
921        /**
922         * The INFORMIX_UNLOAD predefined format.
923         *
924         * @see CSVFormat#INFORMIX_UNLOAD
925         * @since 1.3
926         */
927        InformixUnload(INFORMIX_UNLOAD),
928
929        /**
930         * The INFORMIX_UNLOAD_CSV predefined format.
931         *
932         * @see CSVFormat#INFORMIX_UNLOAD_CSV
933         * @since 1.3
934         */
935        InformixUnloadCsv(INFORMIX_UNLOAD_CSV),
936
937        /**
938         * The MONGODB_CSV predefined format.
939         *
940         * @see CSVFormat#MONGODB_CSV
941         * @since 1.7
942         */
943        MongoDBCsv(MONGODB_CSV),
944
945        /**
946         * The MONGODB_TSV predefined format.
947         *
948         * @see CSVFormat#MONGODB_TSV
949         * @since 1.7
950         */
951        MongoDBTsv(MONGODB_TSV),
952
953        /**
954         * The MYSQL predefined format.
955         *
956         * @see CSVFormat#MYSQL
957         */
958        MySQL(MYSQL),
959
960        /**
961         * The ORACLE predefined format.
962         *
963         * @see CSVFormat#ORACLE
964         */
965        Oracle(ORACLE),
966
967        /**
968         * The POSTGRESQL_CSV predefined format.
969         *
970         * @see CSVFormat#POSTGRESQL_CSV
971         * @since 1.5
972         */
973        PostgreSQLCsv(POSTGRESQL_CSV),
974
975        /**
976         * The POSTGRESQL_TEXT predefined format.
977         *
978         * @see CSVFormat#POSTGRESQL_TEXT
979         */
980        PostgreSQLText(POSTGRESQL_TEXT),
981
982        /**
983         * The RFC4180 predefined format.
984         *
985         * @see CSVFormat#RFC4180
986         */
987        RFC4180(CSVFormat.RFC4180),
988
989        /**
990         * The TDF predefined format.
991         *
992         * @see CSVFormat#TDF
993         */
994        TDF(CSVFormat.TDF);
995
996        private final CSVFormat format;
997
998        Predefined(final CSVFormat format) {
999            this.format = format;
1000        }
1001
1002        /**
1003         * Gets the format.
1004         *
1005         * @return the format.
1006         */
1007        public CSVFormat getFormat() {
1008            return format;
1009        }
1010    }
1011
1012    /**
1013     * Standard Comma Separated Value format, as for {@link #RFC4180} but allowing empty lines.
1014     *
1015     * <p>
1016     * The {@link Builder} settings are:
1017     * </p>
1018     * <ul>
1019     * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')}</li>
1020     * <li>{@link Builder#setQuote(char) setQuote}{@code ('"')}</li>
1021     * <li>{@link Builder#setRecordSeparator(String) setRecordSeparator}{@code ("\r\n")}</li>
1022     * <li>{@link Builder#setIgnoreEmptyLines(boolean) setIgnoreEmptyLines}{@code (true)}</li>
1023     * <li>{@link Builder#setDuplicateHeaderMode(DuplicateHeaderMode) setDuplicateHeaderMode}{@code (DuplicateHeaderMode.ALLOW_ALL)}</li>
1024     * </ul>
1025     *
1026     * @see Predefined#Default
1027     * @see DuplicateHeaderMode#ALLOW_ALL
1028     */
1029    public static final CSVFormat DEFAULT = new CSVFormat(Builder.create());
1030
1031    /**
1032     * <a href="https://support.microsoft.com/en-us/office/import-or-export-text-txt-or-csv-files-5250ac4c-663c-47ce-937b-339e391393ba">Microsoft Excel</a> file
1033     * format (using a comma as the value delimiter). Note that the actual value delimiter used by Excel is locale-dependent, it might be necessary to customize
1034     * this format to accommodate your regional settings.
1035     *
1036     * <p>
1037     * For example for parsing or generating a CSV file on a French system the following format will be used:
1038     * </p>
1039     *
1040     * <pre>
1041     * CSVFormat format = CSVFormat.EXCEL.builder().setDelimiter(';').get();
1042     * </pre>
1043     *
1044     * <p>
1045     * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
1046     * </p>
1047     * <ul>
1048     * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')}</li>
1049     * <li>{@link Builder#setQuote(char) setQuote}{@code ('"')}</li>
1050     * <li>{@link Builder#setRecordSeparator(String) setRecordSeparator}{@code ("\r\n")}</li>
1051     * <li>{@link Builder#setDuplicateHeaderMode(DuplicateHeaderMode) setDuplicateHeaderMode}{@code (DuplicateHeaderMode.ALLOW_ALL)}</li>
1052     * <li>{@link Builder#setIgnoreEmptyLines(boolean) setIgnoreEmptyLines}{@code (false)}</li>
1053     * <li>{@link Builder#setAllowMissingColumnNames(boolean) setAllowMissingColumnNames}{@code (true)}</li>
1054     * <li>{@link Builder#setTrailingData(boolean) setTrailingData}{@code (true)}</li>
1055     * <li>{@link Builder#setLenientEof(boolean) setLenientEof}{@code (true)}</li>
1056     * </ul>
1057     * <p>
1058     * Note: This is currently like {@link #RFC4180} plus {@link Builder#setAllowMissingColumnNames(boolean) Builder#setAllowMissingColumnNames(true)} and
1059     * {@link Builder#setIgnoreEmptyLines(boolean) Builder#setIgnoreEmptyLines(false)}.
1060     * </p>
1061     *
1062     * @see Predefined#Excel
1063     * @see DuplicateHeaderMode#ALLOW_ALL
1064     * @see <a href="https://support.microsoft.com/en-us/office/import-or-export-text-txt-or-csv-files-5250ac4c-663c-47ce-937b-339e391393ba">Microsoft Excel
1065     *      </a>
1066     */
1067    // @formatter:off
1068    public static final CSVFormat EXCEL = DEFAULT.builder()
1069            .setIgnoreEmptyLines(false)
1070            .setAllowMissingColumnNames(true)
1071            .setTrailingData(true)
1072            .setLenientEof(true)
1073            .get();
1074    // @formatter:on
1075
1076    /**
1077     * Default <a href="https://www.ibm.com/docs/en/informix-servers/14.10?topic=statements-unload-statement">Informix CSV UNLOAD</a>
1078     * format used by the {@code UNLOAD TO file_name} operation.
1079     *
1080     * <p>
1081     * This is a comma-delimited format with an LF character as the line separator. Values are not quoted and special characters are escaped with {@code '\'}.
1082     * The default NULL string is {@code "\\N"}.
1083     * </p>
1084     *
1085     * <p>
1086     * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
1087     * </p>
1088     * <ul>
1089     * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')}</li>
1090     * <li>{@link Builder#setEscape(char) setEscape}{@code ('\\')}</li>
1091     * <li>{@link Builder#setQuote(char) setQuote}{@code ('\"')}</li>
1092     * <li>{@link Builder#setRecordSeparator(char) setRecordSeparator}{@code ('\n')}</li>
1093     * </ul>
1094     *
1095     * @see Predefined#MySQL
1096     * @see <a href="https://www.ibm.com/docs/en/informix-servers/14.10?topic=statements-unload-statement">Informix CSV UNLOAD</a>
1097     * @since 1.3
1098     */
1099    // @formatter:off
1100    public static final CSVFormat INFORMIX_UNLOAD = DEFAULT.builder()
1101            .setDelimiter(Constants.PIPE)
1102            .setEscape(Constants.BACKSLASH)
1103            .setQuote(Constants.DOUBLE_QUOTE_CHAR)
1104            .setRecordSeparator(Constants.LF)
1105            .get();
1106    // @formatter:on
1107
1108    /**
1109     * Default <a href="https://www.ibm.com/docs/en/informix-servers/14.10?topic=statements-unload-statement">Informix CSV UNLOAD</a>
1110     * format used by the {@code UNLOAD TO file_name} operation (escaping is disabled.)
1111     *
1112     * <p>
1113     * This is a comma-delimited format with an LF character as the line separator. Values are not quoted and special characters are escaped with {@code '\'}.
1114     * The default NULL string is {@code "\\N"}.
1115     * </p>
1116     *
1117     * <p>
1118     * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
1119     * </p>
1120     * <ul>
1121     * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')}</li>
1122     * <li>{@link Builder#setQuote(char) setQuote}{@code ('\"')}</li>
1123     * <li>{@link Builder#setRecordSeparator(char) setRecordSeparator}{@code ('\n')}</li>
1124     * </ul>
1125     *
1126     * @see Predefined#MySQL
1127     * @see <a href= "http://www.ibm.com/support/knowledgecenter/SSBJG3_2.5.0/com.ibm.gen_busug.doc/c_fgl_InOutSql_UNLOAD.htm">
1128     *      http://www.ibm.com/support/knowledgecenter/SSBJG3_2.5.0/com.ibm.gen_busug.doc/c_fgl_InOutSql_UNLOAD.htm</a>
1129     * @since 1.3
1130     */
1131    // @formatter:off
1132    public static final CSVFormat INFORMIX_UNLOAD_CSV = DEFAULT.builder()
1133            .setDelimiter(Constants.COMMA)
1134            .setQuote(Constants.DOUBLE_QUOTE_CHAR)
1135            .setRecordSeparator(Constants.LF)
1136            .get();
1137    // @formatter:on
1138
1139    /**
1140     * Default MongoDB CSV format used by the {@code mongoexport} operation.
1141     * <p>
1142     * <strong>Parsing is not supported yet.</strong>
1143     * </p>
1144     *
1145     * <p>
1146     * This is a comma-delimited format. Values are double quoted only if needed and special characters are escaped with {@code '"'}. A header line with field
1147     * names is expected.
1148     * </p>
1149     * <p>
1150     * As of 2024-04-05, the MongoDB documentation for {@code mongoimport} states:
1151     * </p>
1152     * <blockquote>The csv parser accepts that data that complies with RFC <a href="https://tools.ietf.org/html/4180">RFC-4180</a>. As a result, backslashes are
1153     * not a valid escape character. If you use double-quotes to enclose fields in the CSV data, you must escape internal double-quote marks by prepending
1154     * another double-quote. </blockquote>
1155     * <p>
1156     * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
1157     * </p>
1158     * <ul>
1159     * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')}</li>
1160     * <li>{@link Builder#setEscape(char) setEscape}{@code ('"')}</li>
1161     * <li>{@link Builder#setQuote(char) setQuote}{@code ('"')}</li>
1162     * <li>{@link Builder#setQuoteMode(QuoteMode) setQuoteMode}{@code (QuoteMode.MINIMAL)}</li>
1163     * </ul>
1164     *
1165     * @see Predefined#MongoDBCsv
1166     * @see QuoteMode#ALL_NON_NULL
1167     * @see <a href="https://docs.mongodb.com/manual/reference/program/mongoexport/">MongoDB mongoexport command documentation</a>
1168     * @since 1.7
1169     */
1170    // @formatter:off
1171    public static final CSVFormat MONGODB_CSV = DEFAULT.builder()
1172            .setDelimiter(Constants.COMMA)
1173            .setEscape(Constants.DOUBLE_QUOTE_CHAR)
1174            .setQuote(Constants.DOUBLE_QUOTE_CHAR)
1175            .setQuoteMode(QuoteMode.MINIMAL)
1176            .get();
1177    // @formatter:off
1178
1179    /**
1180     * Default MongoDB TSV format used by the {@code mongoexport} operation.
1181     * <p>
1182     * <strong>Parsing is not supported yet.</strong>
1183     * </p>
1184     *
1185     * <p>
1186     * This is a tab-delimited format. Values are double quoted only if needed and special
1187     * characters are escaped with {@code '"'}. A header line with field names is expected.
1188     * </p>
1189     *
1190     * <p>
1191     * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
1192     * </p>
1193     * <ul>
1194     * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code ('\t')}</li>
1195     * <li>{@link Builder#setEscape(char) setEscape}{@code ('"')}</li>
1196     * <li>{@link Builder#setQuote(char) setQuote}{@code ('"')}</li>
1197     * <li>{@link Builder#setQuoteMode(QuoteMode) setQuoteMode}{@code (QuoteMode.MINIMAL)}</li>
1198     * <li>{@link Builder#setSkipHeaderRecord(boolean) setSkipHeaderRecord}{@code (false)}</li>
1199     * </ul>
1200     *
1201     * @see Predefined#MongoDBCsv
1202     * @see QuoteMode#ALL_NON_NULL
1203     * @see <a href="https://docs.mongodb.com/manual/reference/program/mongoexport/">MongoDB mongoexport command
1204     *          documentation</a>
1205     * @since 1.7
1206     */
1207    // @formatter:off
1208    public static final CSVFormat MONGODB_TSV = DEFAULT.builder()
1209            .setDelimiter(Constants.TAB)
1210            .setEscape(Constants.DOUBLE_QUOTE_CHAR)
1211            .setQuote(Constants.DOUBLE_QUOTE_CHAR)
1212            .setQuoteMode(QuoteMode.MINIMAL)
1213            .setSkipHeaderRecord(false)
1214            .get();
1215    // @formatter:off
1216
1217    /**
1218     * Default <a href="https://dev.mysql.com/doc/refman/8.0/en/mysqldump-delimited-text.html">MySQL</a>
1219     * format used by the {@code SELECT INTO OUTFILE} and {@code LOAD DATA INFILE} operations.
1220     *
1221     * <p>
1222     * This is a tab-delimited format with an LF character as the line separator. Values are not quoted and special
1223     * characters are escaped with {@code '\'}. The default NULL string is {@code "\\N"}.
1224     * </p>
1225     *
1226     * <p>
1227     * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
1228     * </p>
1229     * <ul>
1230     * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code ('\t')}</li>
1231     * <li>{@link Builder#setEscape(char) setEscape}{@code ('\\')}</li>
1232     * <li>{@link Builder#setIgnoreEmptyLines(boolean) setIgnoreEmptyLines}{@code (false)}</li>
1233     * <li>{@link Builder#setQuote(Character) setQuote}{@code (null)}</li>
1234     * <li>{@link Builder#setRecordSeparator(char) setRecordSeparator}{@code ('\n')}</li>
1235     * <li>{@link Builder#setNullString(String) setNullString}{@code ("\\N")}</li>
1236     * <li>{@link Builder#setQuoteMode(QuoteMode) setQuoteMode}{@code (QuoteMode.ALL_NON_NULL)}</li>
1237     * </ul>
1238     *
1239     * @see Predefined#MySQL
1240     * @see QuoteMode#ALL_NON_NULL
1241     * @see <a href="https://dev.mysql.com/doc/refman/8.0/en/mysqldump-delimited-text.html">MySQL</a>
1242     */
1243    // @formatter:off
1244    public static final CSVFormat MYSQL = DEFAULT.builder()
1245            .setDelimiter(Constants.TAB)
1246            .setEscape(Constants.BACKSLASH)
1247            .setIgnoreEmptyLines(false)
1248            .setQuote(null)
1249            .setRecordSeparator(Constants.LF)
1250            .setNullString(Constants.SQL_NULL_STRING)
1251            .setQuoteMode(QuoteMode.ALL_NON_NULL)
1252            .get();
1253    // @formatter:off
1254
1255    /**
1256     * Default
1257     * <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/sutil/oracle-sql-loader-control-file-contents.html#GUID-D1762699-8154-40F6-90DE-EFB8EB6A9AB0">Oracle</a>
1258     * format used by the SQL*Loader utility.
1259     *
1260     * <p>
1261     * This is a comma-delimited format with the system line separator character as the record separator. Values are
1262     * double quoted when needed and special characters are escaped with {@code '"'}. The default NULL string is
1263     * {@code ""}. Values are trimmed.
1264     * </p>
1265     *
1266     * <p>
1267     * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
1268     * </p>
1269     * <ul>
1270     * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')} // default is {@code FIELDS TERMINATED BY ','}}</li>
1271     * <li>{@link Builder#setEscape(char) setEscape}{@code ('\\')}</li>
1272     * <li>{@link Builder#setIgnoreEmptyLines(boolean) setIgnoreEmptyLines}{@code (false)}</li>
1273     * <li>{@link Builder#setQuote(char) setQuote}{@code ('"')} // default is {@code OPTIONALLY ENCLOSED BY '"'}}</li>
1274     * <li>{@link Builder#setNullString(String) setNullString}{@code ("\\N")}</li>
1275     * <li>{@link Builder#setTrim(boolean) setTrim}{@code (true)}</li>
1276     * <li>{@link Builder#setRecordSeparator(String) setRecordSeparator}{@code (System.lineSeparator())}</li>
1277     * <li>{@link Builder#setQuoteMode(QuoteMode) setQuoteMode}{@code (QuoteMode.MINIMAL)}</li>
1278     * </ul>
1279     *
1280     * @see Predefined#Oracle
1281     * @see QuoteMode#MINIMAL
1282     * @see <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/sutil/oracle-sql-loader-control-file-contents.html#GUID-D1762699-8154-40F6-90DE-EFB8EB6A9AB0">Oracle CSV Format Specification</a>
1283     * @since 1.6
1284     */
1285    // @formatter:off
1286    public static final CSVFormat ORACLE = DEFAULT.builder()
1287            .setDelimiter(Constants.COMMA)
1288            .setEscape(Constants.BACKSLASH)
1289            .setIgnoreEmptyLines(false)
1290            .setQuote(Constants.DOUBLE_QUOTE_CHAR)
1291            .setNullString(Constants.SQL_NULL_STRING)
1292            .setTrim(true)
1293            .setRecordSeparator(System.lineSeparator())
1294            .setQuoteMode(QuoteMode.MINIMAL)
1295            .get();
1296    // @formatter:off
1297
1298    /**
1299     * Default <a href="https://www.postgresql.org/docs/current/static/sql-copy.html">PostgreSQL CSV</a> format used by the {@code COPY} operation.
1300     *
1301     * <p>
1302     * This is a comma-delimited format with an LF character as the line separator. Values are double quoted and special
1303     * characters are not escaped. The default NULL string is {@code ""}.
1304     * </p>
1305     *
1306     * <p>
1307     * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
1308     * </p>
1309     * <ul>
1310     * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')}</li>
1311     * <li>{@link Builder#setEscape(Character) setEscape}{@code (null)}</li>
1312     * <li>{@link Builder#setIgnoreEmptyLines(boolean) setIgnoreEmptyLines}{@code (false)}</li>
1313     * <li>{@link Builder#setQuote(char) setQuote}{@code ('"')}</li>
1314     * <li>{@link Builder#setRecordSeparator(char) setRecordSeparator}{@code ('\n')}</li>
1315     * <li>{@link Builder#setNullString(String) setNullString}{@code ("")}</li>
1316     * <li>{@link Builder#setQuoteMode(QuoteMode) setQuoteMode}{@code (QuoteMode.ALL_NON_NULL)}</li>
1317     * </ul>
1318     *
1319     * @see Predefined#MySQL
1320     * @see QuoteMode#ALL_NON_NULL
1321     * @see <a href="https://www.postgresql.org/docs/current/static/sql-copy.html">PostgreSQL CSV</a>
1322     * @since 1.5
1323     */
1324    // @formatter:off
1325    public static final CSVFormat POSTGRESQL_CSV = DEFAULT.builder()
1326            .setDelimiter(Constants.COMMA)
1327            .setEscape(null)
1328            .setIgnoreEmptyLines(false)
1329            .setQuote(Constants.DOUBLE_QUOTE_CHAR)
1330            .setRecordSeparator(Constants.LF)
1331            .setNullString(Constants.EMPTY)
1332            .setQuoteMode(QuoteMode.ALL_NON_NULL)
1333            .get();
1334    // @formatter:off
1335
1336    /**
1337     * Default <a href="https://www.postgresql.org/docs/current/static/sql-copy.html">PostgreSQL Text</a> format used by the {@code COPY} operation.
1338     *
1339     * <p>
1340     * This is a tab-delimited format with an LF character as the line separator. Values are not quoted and special
1341     * characters are escaped with {@code '\\'}. The default NULL string is {@code "\\N"}.
1342     * </p>
1343     *
1344     * <p>
1345     * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
1346     * </p>
1347     * <ul>
1348     * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code ('\t')}</li>
1349     * <li>{@link Builder#setEscape(char) setEscape}{@code ('\\')}</li>
1350     * <li>{@link Builder#setIgnoreEmptyLines(boolean) setIgnoreEmptyLines}{@code (false)}</li>
1351     * <li>{@link Builder#setQuote(Character) setQuote}{@code (null)}</li>
1352     * <li>{@link Builder#setRecordSeparator(char) setRecordSeparator}{@code ('\n')}</li>
1353     * <li>{@link Builder#setNullString(String) setNullString}{@code ("\\N")}</li>
1354     * <li>{@link Builder#setQuoteMode(QuoteMode) setQuoteMode}{@code (QuoteMode.ALL_NON_NULL)}</li>
1355     * </ul>
1356     *
1357     * @see Predefined#MySQL
1358     * @see QuoteMode#ALL_NON_NULL
1359     * @see <a href="https://www.postgresql.org/docs/current/static/sql-copy.html">PostgreSQL Text</a>
1360     * @since 1.5
1361     */
1362    // @formatter:off
1363    public static final CSVFormat POSTGRESQL_TEXT = DEFAULT.builder()
1364            .setDelimiter(Constants.TAB)
1365            .setEscape(Constants.BACKSLASH)
1366            .setIgnoreEmptyLines(false)
1367            .setQuote(null)
1368            .setRecordSeparator(Constants.LF)
1369            .setNullString(Constants.SQL_NULL_STRING)
1370            .setQuoteMode(QuoteMode.ALL_NON_NULL)
1371            .get();
1372    // @formatter:off
1373
1374    /**
1375     * Comma separated format as defined by <a href="https://tools.ietf.org/html/rfc4180">RFC 4180</a>.
1376     *
1377     * <p>
1378     * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
1379     * </p>
1380     * <ul>
1381     * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')}</li>
1382     * <li>{@link Builder#setQuote(char) setQuote}{@code ('"')}</li>
1383     * <li>{@link Builder#setRecordSeparator(String) setRecordSeparator}{@code ("\r\n")}</li>
1384     * <li>{@link Builder#setIgnoreEmptyLines(boolean) setIgnoreEmptyLines}{@code (false)}</li>
1385     * </ul>
1386     *
1387     * @see Predefined#RFC4180
1388     * @see <a href="https://tools.ietf.org/html/rfc4180">RFC 4180</a>
1389     */
1390    public static final CSVFormat RFC4180 = DEFAULT.builder().setIgnoreEmptyLines(false).get();
1391
1392    private static final long serialVersionUID = 2L;
1393
1394    /**
1395     * Tab-delimited format (<a href="https://en.wikipedia.org/wiki/Tab-separated_values">TDF</a>).
1396     *
1397     * <p>
1398     * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
1399     * </p>
1400     * <ul>
1401     * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code ('\t')}</li>
1402     * <li>{@link Builder#setIgnoreSurroundingSpaces(boolean) setIgnoreSurroundingSpaces}{@code (true)}</li>
1403     * </ul>
1404     *
1405     * @see Predefined#TDF
1406     * @see <a href="https://en.wikipedia.org/wiki/Tab-separated_values">TDF</a>
1407     */
1408    // @formatter:off
1409    public static final CSVFormat TDF = DEFAULT.builder()
1410            .setDelimiter(Constants.TAB)
1411            .setIgnoreSurroundingSpaces(true)
1412            .get();
1413    // @formatter:on
1414
1415    /**
1416     * Null-safe clone of an array.
1417     *
1418     * @param <T>    The array element type.
1419     * @param values the source array
1420     * @return the cloned array.
1421     */
1422    @SafeVarargs
1423    static <T> T[] clone(final T... values) {
1424        return values == null ? null : values.clone();
1425    }
1426
1427    /**
1428     * Returns true if the given string contains the search char.
1429     *
1430     * @param source   the string to check.
1431     * @param searchCh the character to search.
1432     * @return true if {@code c} contains a line break character
1433     */
1434    private static boolean contains(final String source, final char searchCh) {
1435        return Objects.requireNonNull(source, "source").indexOf(searchCh) >= 0;
1436    }
1437
1438    /**
1439     * Returns true if the given string contains a line break character.
1440     *
1441     * @param source the string to check.
1442     * @return true if {@code c} contains a line break character.
1443     */
1444    private static boolean containsLineBreak(final String source) {
1445        return contains(source, Constants.CR) || contains(source, Constants.LF);
1446    }
1447
1448    /**
1449     * Creates a null-safe copy of the given instance.
1450     *
1451     * @return a copy of the given instance or null if the input is null.
1452     */
1453    static CSVFormat copy(final CSVFormat format) {
1454        return format != null ? format.copy() : null;
1455    }
1456
1457    static boolean isBlank(final String value) {
1458        return value == null || value.trim().isEmpty();
1459    }
1460
1461    /**
1462     * Returns true if the given character is a line break character.
1463     *
1464     * @param c the character to check.
1465     * @return true if {@code c} is a line break character.
1466     */
1467    private static boolean isLineBreak(final char c) {
1468        return c == Constants.LF || c == Constants.CR;
1469    }
1470
1471    /**
1472     * Returns true if the given character is a line break character.
1473     *
1474     * @param c the character to check, may be null.
1475     * @return true if {@code c} is a line break character (and not null).
1476     */
1477    private static boolean isLineBreak(final Character c) {
1478        return c != null && isLineBreak(c.charValue()); // Explicit (un)boxing is intentional
1479    }
1480
1481    /** Same test as in as {@link String#trim()}. */
1482    private static boolean isTrimChar(final char ch) {
1483        return ch <= Constants.SP;
1484    }
1485
1486    /** Same test as in as {@link String#trim()}. */
1487    private static boolean isTrimChar(final CharSequence charSequence, final int pos) {
1488        return isTrimChar(charSequence.charAt(pos));
1489    }
1490
1491    /**
1492     * Creates a new CSV format with the specified delimiter.
1493     *
1494     * <p>
1495     * Use this method if you want to create a CSVFormat from scratch. All fields but the delimiter will be initialized with null/false.
1496     * </p>
1497     *
1498     * @param delimiter the char used for value separation, must not be a line break character
1499     * @return a new CSV format.
1500     * @throws IllegalArgumentException if the delimiter is a line break character
1501     * @see #DEFAULT
1502     * @see #RFC4180
1503     * @see #MYSQL
1504     * @see #EXCEL
1505     * @see #TDF
1506     */
1507    public static CSVFormat newFormat(final char delimiter) {
1508        return new CSVFormat(new Builder().setDelimiter(delimiter));
1509    }
1510
1511    static String[] toStringArray(final Object[] values) {
1512        if (values == null) {
1513            return null;
1514        }
1515        final String[] strings = new String[values.length];
1516        Arrays.setAll(strings, i -> Objects.toString(values[i], null));
1517        return strings;
1518    }
1519
1520    static CharSequence trim(final CharSequence charSequence) {
1521        if (charSequence instanceof String) {
1522            return ((String) charSequence).trim();
1523        }
1524        final int count = charSequence.length();
1525        int len = count;
1526        int pos = 0;
1527
1528        while (pos < len && isTrimChar(charSequence, pos)) {
1529            pos++;
1530        }
1531        while (pos < len && isTrimChar(charSequence, len - 1)) {
1532            len--;
1533        }
1534        return pos > 0 || len < count ? charSequence.subSequence(pos, len) : charSequence;
1535    }
1536
1537    /**
1538     * Gets one of the predefined formats from {@link CSVFormat.Predefined}.
1539     *
1540     * @param format name
1541     * @return one of the predefined formats
1542     * @since 1.2
1543     */
1544    public static CSVFormat valueOf(final String format) {
1545        return CSVFormat.Predefined.valueOf(format).getFormat();
1546    }
1547
1548    /** How duplicate headers are handled. */
1549    private final DuplicateHeaderMode duplicateHeaderMode;
1550
1551    /** Whether missing column names are allowed when parsing the header line. */
1552    private final boolean allowMissingColumnNames;
1553
1554    /** Whether to flush on close. */
1555    private final boolean autoFlush;
1556
1557    /** Set to null if commenting is disabled. */
1558    private final Character commentMarker;
1559
1560    /** The character delimiting the values (typically ";", "," or "\t"). */
1561    private final String delimiter;
1562
1563    /** Set to null if escaping is disabled. */
1564    private final Character escapeCharacter;
1565
1566    /** Array of header column names. */
1567    private final String[] headers;
1568
1569    /** Array of header comment lines. */
1570    private final String[] headerComments;
1571
1572    /** Whether empty lines between records are ignored when parsing input. */
1573    private final boolean ignoreEmptyLines;
1574
1575    /** Should ignore header names case. */
1576    private final boolean ignoreHeaderCase;
1577
1578    /** Should leading/trailing spaces be ignored around values?. */
1579    private final boolean ignoreSurroundingSpaces;
1580
1581    /** The string to be used for null values. */
1582    private final String nullString;
1583
1584    /** Set to null if quoting is disabled. */
1585    private final Character quoteCharacter;
1586
1587    /** Set to {@code quoteCharacter + nullString + quoteCharacter} */
1588    private final String quotedNullString;
1589
1590    /** The quote policy output fields. */
1591    private final QuoteMode quoteMode;
1592
1593    /** For output. */
1594    private final String recordSeparator;
1595
1596    /** Whether to skip the header record. */
1597    private final boolean skipHeaderRecord;
1598
1599    /** Whether reading end-of-file is allowed even when input is malformed, helps Excel compatibility. */
1600    private final boolean lenientEof;
1601
1602    /** Whether reading trailing data is allowed in records, helps Excel compatibility. */
1603    private final boolean trailingData;
1604
1605    /** Whether to add a trailing delimiter. */
1606    private final boolean trailingDelimiter;
1607
1608    /** Whether to trim leading and trailing blanks. */
1609    private final boolean trim;
1610
1611    /** The maximum number of rows to process, excluding the header row. */
1612    private final long maxRows;
1613
1614    private CSVFormat(final Builder builder) {
1615        this.allowMissingColumnNames = builder.allowMissingColumnNames;
1616        this.autoFlush = builder.autoFlush;
1617        this.commentMarker = builder.commentMarker;
1618        this.delimiter = builder.delimiter;
1619        this.duplicateHeaderMode = builder.duplicateHeaderMode;
1620        this.escapeCharacter = builder.escapeCharacter;
1621        this.headerComments = builder.headerComments;
1622        this.headers = builder.headers;
1623        this.ignoreEmptyLines = builder.ignoreEmptyLines;
1624        this.ignoreHeaderCase = builder.ignoreHeaderCase;
1625        this.ignoreSurroundingSpaces = builder.ignoreSurroundingSpaces;
1626        this.lenientEof = builder.lenientEof;
1627        this.maxRows = builder.maxRows;
1628        this.nullString = builder.nullString;
1629        this.quoteCharacter = builder.quoteCharacter;
1630        this.quoteMode = builder.quoteMode;
1631        this.quotedNullString = builder.quotedNullString;
1632        this.recordSeparator = builder.recordSeparator;
1633        this.skipHeaderRecord = builder.skipHeaderRecord;
1634        this.trailingData = builder.trailingData;
1635        this.trailingDelimiter = builder.trailingDelimiter;
1636        this.trim = builder.trim;
1637        validate();
1638    }
1639
1640    private void append(final char c, final Appendable appendable) throws IOException {
1641        // try {
1642        appendable.append(c);
1643        // } catch (final IOException e) {
1644        // throw new UncheckedIOException(e);
1645        // }
1646    }
1647
1648    private void append(final CharSequence csq, final Appendable appendable) throws IOException {
1649        // try {
1650        appendable.append(csq);
1651        // } catch (final IOException e) {
1652        // throw new UncheckedIOException(e);
1653        // }
1654    }
1655
1656    /**
1657     * Creates a new Builder for this instance.
1658     *
1659     * @return a new Builder.
1660     */
1661    public Builder builder() {
1662        return Builder.create(this);
1663    }
1664
1665    /**
1666     * Creates a copy of this instance.
1667     *
1668     * @return a copy of this instance.
1669     */
1670    CSVFormat copy() {
1671        return builder().get();
1672    }
1673
1674    @Override
1675    public boolean equals(final Object obj) {
1676        if (this == obj) {
1677            return true;
1678        }
1679        if (obj == null) {
1680            return false;
1681        }
1682        if (getClass() != obj.getClass()) {
1683            return false;
1684        }
1685        final CSVFormat other = (CSVFormat) obj;
1686        return allowMissingColumnNames == other.allowMissingColumnNames && autoFlush == other.autoFlush &&
1687                Objects.equals(commentMarker, other.commentMarker) && Objects.equals(delimiter, other.delimiter) &&
1688                duplicateHeaderMode == other.duplicateHeaderMode && Objects.equals(escapeCharacter, other.escapeCharacter) &&
1689                Arrays.equals(headerComments, other.headerComments) && Arrays.equals(headers, other.headers) &&
1690                ignoreEmptyLines == other.ignoreEmptyLines && ignoreHeaderCase == other.ignoreHeaderCase &&
1691                ignoreSurroundingSpaces == other.ignoreSurroundingSpaces && lenientEof == other.lenientEof &&
1692                Objects.equals(nullString, other.nullString) && Objects.equals(quoteCharacter, other.quoteCharacter) &&
1693                quoteMode == other.quoteMode && Objects.equals(quotedNullString, other.quotedNullString) &&
1694                Objects.equals(recordSeparator, other.recordSeparator) && skipHeaderRecord == other.skipHeaderRecord &&
1695                trailingData == other.trailingData && trailingDelimiter == other.trailingDelimiter && trim == other.trim;
1696    }
1697
1698    private void escape(final char c, final Appendable appendable) throws IOException {
1699        append(escapeCharacter.charValue(), appendable); // Explicit (un)boxing is intentional
1700        append(c, appendable);
1701    }
1702
1703    /**
1704     * Formats the specified values as a CSV record string.
1705     *
1706     * @param values the values to format.
1707     * @return the formatted values.
1708     */
1709    public String format(final Object... values) {
1710        return Uncheck.get(() -> format_(values));
1711    }
1712
1713    private String format_(final Object... values) throws IOException {
1714        final StringWriter out = new StringWriter();
1715        try (CSVPrinter csvPrinter = new CSVPrinter(out, this)) {
1716            csvPrinter.printRecord(values);
1717            final String res = out.toString();
1718            final int len = recordSeparator != null ? res.length() - recordSeparator.length() : res.length();
1719            return res.substring(0, len);
1720        }
1721    }
1722
1723    /**
1724     * Gets whether duplicate names are allowed in the headers.
1725     *
1726     * @return whether duplicate header names are allowed
1727     * @since 1.7
1728     * @deprecated Use {@link #getDuplicateHeaderMode()}.
1729     */
1730    @Deprecated
1731    public boolean getAllowDuplicateHeaderNames() {
1732        return duplicateHeaderMode == DuplicateHeaderMode.ALLOW_ALL;
1733    }
1734
1735    /**
1736     * Gets whether missing column names are allowed when parsing the header line.
1737     *
1738     * @return {@code true} if missing column names are allowed when parsing the header line, {@code false} to throw an {@link IllegalArgumentException}.
1739     */
1740    public boolean getAllowMissingColumnNames() {
1741        return allowMissingColumnNames;
1742    }
1743
1744    /**
1745     * Gets whether to flush on close.
1746     *
1747     * @return whether to flush on close.
1748     * @since 1.6
1749     */
1750    public boolean getAutoFlush() {
1751        return autoFlush;
1752    }
1753
1754    /**
1755     * Gets the comment marker character, {@code null} disables comments.
1756     * <p>
1757     * The comment start character is only recognized at the start of a line.
1758     * </p>
1759     * <p>
1760     * Comments are printed first, before headers.
1761     * </p>
1762     * <p>
1763     * Use {@link Builder#setCommentMarker(char)} or {@link Builder#setCommentMarker(Character)} to set the comment marker written at the start of each comment
1764     * line.
1765     * </p>
1766     * <p>
1767     * If the comment marker is not set, then the header comments are ignored.
1768     * </p>
1769     * <p>
1770     * For example:
1771     * </p>
1772     *
1773     * <pre>
1774     * builder.setCommentMarker('#').setHeaderComments("Generated by Apache Commons CSV", Instant.ofEpochMilli(0));
1775     * </pre>
1776     * <p>
1777     * writes:
1778     * </p>
1779     *
1780     * <pre>
1781     * # Generated by Apache Commons CSV.
1782     * # 1970-01-01T00:00:00Z
1783     * </pre>
1784     *
1785     * @return the comment start marker, may be {@code null}
1786     */
1787    public Character getCommentMarker() {
1788        return commentMarker;
1789    }
1790
1791    /**
1792     * Gets the first character delimiting the values (typically ';', ',' or '\t').
1793     *
1794     * @return the first delimiter character.
1795     * @deprecated Use {@link #getDelimiterString()}.
1796     */
1797    @Deprecated
1798    public char getDelimiter() {
1799        return delimiter.charAt(0);
1800    }
1801
1802    /**
1803     * Gets the character delimiting the values (typically ";", "," or "\t").
1804     *
1805     * @return the delimiter.
1806     */
1807    char[] getDelimiterCharArray() {
1808        return delimiter.toCharArray();
1809    }
1810
1811    /**
1812     * Gets the character delimiting the values (typically ";", "," or "\t").
1813     *
1814     * @return the delimiter.
1815     * @since 1.9.0
1816     */
1817    public String getDelimiterString() {
1818        return delimiter;
1819    }
1820
1821    /**
1822     * Gets how duplicate headers are handled.
1823     *
1824     * @return if duplicate header values are allowed, allowed conditionally, or disallowed.
1825     * @since 1.10.0
1826     */
1827    public DuplicateHeaderMode getDuplicateHeaderMode() {
1828        return duplicateHeaderMode;
1829    }
1830
1831    /**
1832     * Gets the escape character.
1833     *
1834     * @return the escape character, may be {@code 0}
1835     */
1836    char getEscapeChar() {
1837        return escapeCharacter != null ? escapeCharacter.charValue() : 0; // Explicit (un)boxing is intentional
1838    }
1839
1840    /**
1841     * Gets the escape character.
1842     *
1843     * @return the escape character, may be {@code null}
1844     */
1845    public Character getEscapeCharacter() {
1846        return escapeCharacter;
1847    }
1848
1849    /**
1850     * Gets a copy of the header array.
1851     *
1852     * @return a copy of the header array; {@code null} if disabled, the empty array if to be read from the file
1853     */
1854    public String[] getHeader() {
1855        return headers != null ? headers.clone() : null;
1856    }
1857
1858    /**
1859     * Gets a copy of the header comment array to write before the CSV data.
1860     * <p>
1861     * This setting is ignored by the parser.
1862     * </p>
1863     * <p>
1864     * Comments are printed first, before headers.
1865     * </p>
1866     * <p>
1867     * Use {@link Builder#setCommentMarker(char)} or {@link Builder#setCommentMarker(Character)} to set the comment marker written at the start of each comment
1868     * line.
1869     * </p>
1870     * <p>
1871     * If the comment marker is not set, then the header comments are ignored.
1872     * </p>
1873     * <p>
1874     * For example:
1875     * </p>
1876     *
1877     * <pre>
1878     * builder.setCommentMarker('#').setHeaderComments("Generated by Apache Commons CSV", Instant.ofEpochMilli(0));
1879     * </pre>
1880     * <p>
1881     * writes:
1882     * </p>
1883     *
1884     * <pre>
1885     * # Generated by Apache Commons CSV.
1886     * # 1970-01-01T00:00:00Z
1887     * </pre>
1888     *
1889     * @return a copy of the header comment array; {@code null} if disabled.
1890     */
1891    public String[] getHeaderComments() {
1892        return headerComments != null ? headerComments.clone() : null;
1893    }
1894
1895    /**
1896     * Gets whether empty lines between records are ignored when parsing input.
1897     *
1898     * @return {@code true} if empty lines between records are ignored, {@code false} if they are turned into empty records.
1899     */
1900    public boolean getIgnoreEmptyLines() {
1901        return ignoreEmptyLines;
1902    }
1903
1904    /**
1905     * Gets whether header names will be accessed ignoring case when parsing input.
1906     *
1907     * @return {@code true} if header names cases are ignored, {@code false} if they are case-sensitive.
1908     * @since 1.3
1909     */
1910    public boolean getIgnoreHeaderCase() {
1911        return ignoreHeaderCase;
1912    }
1913
1914    /**
1915     * Gets whether spaces around values are ignored when parsing input.
1916     *
1917     * @return {@code true} if spaces around values are ignored, {@code false} if they are treated as part of the value.
1918     */
1919    public boolean getIgnoreSurroundingSpaces() {
1920        return ignoreSurroundingSpaces;
1921    }
1922
1923    /**
1924     * Gets whether reading end-of-file is allowed even when input is malformed, helps Excel compatibility.
1925     *
1926     * @return whether reading end-of-file is allowed even when input is malformed, helps Excel compatibility.
1927     * @since 1.11.0
1928     */
1929    public boolean getLenientEof() {
1930        return lenientEof;
1931    }
1932
1933    /**
1934     * Gets the maximum number of rows to process, excluding the header row.
1935     * <p>
1936     * Values less than or equal to 0 mean no limit.
1937     * </p>
1938     *
1939     * @return The maximum number of rows to process, excluding the header row.
1940     * @since 1.14.0
1941     */
1942    public long getMaxRows() {
1943        return maxRows;
1944    }
1945
1946    /**
1947     * Gets the String to convert to and from {@code null}.
1948     * <ul>
1949     * <li><strong>Reading:</strong> Converts strings equal to the given {@code nullString} to {@code null} when reading records.</li>
1950     * <li><strong>Writing:</strong> Writes {@code null} as the given {@code nullString} when writing records.</li>
1951     * </ul>
1952     *
1953     * @return the String to convert to and from {@code null}. No substitution occurs if {@code null}
1954     */
1955    public String getNullString() {
1956        return nullString;
1957    }
1958
1959    /**
1960     * Gets the character used to encapsulate values containing special characters.
1961     *
1962     * @return the quoteChar character, may be {@code null}
1963     */
1964    public Character getQuoteCharacter() {
1965        return quoteCharacter;
1966    }
1967
1968    /**
1969     * Gets the quote policy output fields.
1970     *
1971     * @return the quote policy
1972     */
1973    public QuoteMode getQuoteMode() {
1974        return quoteMode;
1975    }
1976
1977    /**
1978     * Gets the record separator delimiting output records.
1979     *
1980     * @return the record separator
1981     */
1982    public String getRecordSeparator() {
1983        return recordSeparator;
1984    }
1985
1986    /**
1987     * Gets whether to skip the header record.
1988     *
1989     * @return whether to skip the header record.
1990     */
1991    public boolean getSkipHeaderRecord() {
1992        return skipHeaderRecord;
1993    }
1994
1995    /**
1996     * Gets whether reading trailing data is allowed in records, helps Excel compatibility.
1997     *
1998     * @return whether reading trailing data is allowed in records, helps Excel compatibility.
1999     * @since 1.11.0
2000     */
2001    public boolean getTrailingData() {
2002        return trailingData;
2003    }
2004
2005    /**
2006     * Gets whether to add a trailing delimiter.
2007     *
2008     * @return whether to add a trailing delimiter.
2009     * @since 1.3
2010     */
2011    public boolean getTrailingDelimiter() {
2012        return trailingDelimiter;
2013    }
2014
2015    /**
2016     * Gets whether to trim leading and trailing blanks. This is used by {@link #print(Object, Appendable, boolean)} Also by {CSVParser#addRecordValue(boolean)}
2017     *
2018     * @return whether to trim leading and trailing blanks.
2019     */
2020    public boolean getTrim() {
2021        return trim;
2022    }
2023
2024    @Override
2025    public int hashCode() {
2026        final int prime = 31;
2027        int result = 1;
2028        result = prime * result + Arrays.hashCode(headerComments);
2029        result = prime * result + Arrays.hashCode(headers);
2030        return prime * result + Objects.hash(allowMissingColumnNames, autoFlush, commentMarker, delimiter, duplicateHeaderMode, escapeCharacter,
2031                ignoreEmptyLines, ignoreHeaderCase, ignoreSurroundingSpaces, lenientEof, nullString, quoteCharacter, quoteMode, quotedNullString,
2032                recordSeparator, skipHeaderRecord, trailingData, trailingDelimiter, trim);
2033    }
2034
2035    /**
2036     * Tests whether comments are supported by this format.
2037     *
2038     * Note that the comment introducer character is only recognized at the start of a line.
2039     *
2040     * @return {@code true} is comments are supported, {@code false} otherwise
2041     */
2042    public boolean isCommentMarkerSet() {
2043        return commentMarker != null;
2044    }
2045
2046    /**
2047     * Tests whether the next characters constitute a delimiter
2048     *
2049     * @param ch0             the first char (index 0).
2050     * @param charSeq         the match char sequence
2051     * @param startIndex      where start to match
2052     * @param delimiter       the delimiter
2053     * @param delimiterLength the delimiter length
2054     * @return true if the match is successful
2055     */
2056    private boolean isDelimiter(final char ch0, final CharSequence charSeq, final int startIndex, final char[] delimiter, final int delimiterLength) {
2057        if (ch0 != delimiter[0]) {
2058            return false;
2059        }
2060        final int len = charSeq.length();
2061        if (startIndex + delimiterLength > len) {
2062            return false;
2063        }
2064        for (int i = 1; i < delimiterLength; i++) {
2065            if (charSeq.charAt(startIndex + i) != delimiter[i]) {
2066                return false;
2067            }
2068        }
2069        return true;
2070    }
2071
2072    /**
2073     * Tests whether escapes are being processed.
2074     *
2075     * @return {@code true} if escapes are processed
2076     */
2077    public boolean isEscapeCharacterSet() {
2078        return escapeCharacter != null;
2079    }
2080
2081    /**
2082     * Tests whether a null string has been defined.
2083     *
2084     * @return {@code true} if a nullString is defined
2085     */
2086    public boolean isNullStringSet() {
2087        return nullString != null;
2088    }
2089
2090    /**
2091     * Tests whether a quoteChar has been defined.
2092     *
2093     * @return {@code true} if a quoteChar is defined
2094     */
2095    public boolean isQuoteCharacterSet() {
2096        return quoteCharacter != null;
2097    }
2098
2099    <T> IOStream<T> limit(final IOStream<T> stream) {
2100        return useMaxRows() ? stream.limit(getMaxRows()) : stream;
2101    }
2102
2103    /**
2104     * Parses the specified content.
2105     *
2106     * <p>
2107     * See also the various static parse methods on {@link CSVParser}.
2108     * </p>
2109     *
2110     * @param reader the input stream
2111     * @return a parser over a stream of {@link CSVRecord}s.
2112     * @throws IOException  If an I/O error occurs
2113     * @throws CSVException Thrown on invalid input.
2114     */
2115    public CSVParser parse(final Reader reader) throws IOException {
2116        return CSVParser.builder().setReader(reader).setFormat(this).get();
2117    }
2118
2119    /**
2120     * Prints to the specified output.
2121     *
2122     * <p>
2123     * See also {@link CSVPrinter}.
2124     * </p>
2125     *
2126     * @param out the output.
2127     * @return a printer to an output.
2128     * @throws IOException thrown if the optional header cannot be printed.
2129     */
2130    public CSVPrinter print(final Appendable out) throws IOException {
2131        return new CSVPrinter(out, this);
2132    }
2133
2134    /**
2135     * Prints to the specified {@code File} with given {@code Charset}.
2136     *
2137     * <p>
2138     * See also {@link CSVPrinter}.
2139     * </p>
2140     *
2141     * @param out     the output.
2142     * @param charset A charset.
2143     * @return a printer to an output.
2144     * @throws IOException thrown if the optional header cannot be printed.
2145     * @since 1.5
2146     */
2147    public CSVPrinter print(final File out, final Charset charset) throws IOException {
2148        return print(out.toPath(), charset);
2149    }
2150
2151    private void print(final InputStream inputStream, final Appendable out, final boolean newRecord) throws IOException {
2152        // InputStream is never null here
2153        // There is nothing to escape when quoting is used which is the default.
2154        if (!newRecord) {
2155            append(getDelimiterString(), out);
2156        }
2157        final boolean quoteCharacterSet = isQuoteCharacterSet();
2158        if (quoteCharacterSet) {
2159            append(getQuoteCharacter().charValue(), out); // Explicit (un)boxing is intentional
2160        }
2161        // Stream the input to the output without reading or holding the whole value in memory.
2162        // AppendableOutputStream cannot "close" an Appendable.
2163        try (OutputStream outputStream = new Base64OutputStream(new AppendableOutputStream<>(out))) {
2164            IOUtils.copy(inputStream, outputStream);
2165        }
2166        if (quoteCharacterSet) {
2167            append(getQuoteCharacter().charValue(), out); // Explicit (un)boxing is intentional
2168        }
2169    }
2170
2171    /**
2172     * Prints the {@code value} as the next value on the line to {@code out}. The value will be escaped or encapsulated as needed. Useful when one wants to
2173     * avoid creating CSVPrinters. Trims the value if {@link #getTrim()} is true.
2174     *
2175     * @param value     value to output.
2176     * @param out       where to print the value.
2177     * @param newRecord if this a new record.
2178     * @throws IOException If an I/O error occurs.
2179     * @since 1.4
2180     */
2181    public synchronized void print(final Object value, final Appendable out, final boolean newRecord) throws IOException {
2182        // null values are considered empty
2183        // Only call CharSequence.toString() if you have to, helps GC-free use cases.
2184        CharSequence charSequence;
2185        if (value == null) {
2186            // https://issues.apache.org/jira/browse/CSV-203
2187            if (null == nullString) {
2188                charSequence = Constants.EMPTY;
2189            } else if (QuoteMode.ALL == quoteMode) {
2190                charSequence = quotedNullString;
2191            } else {
2192                charSequence = nullString;
2193            }
2194        } else if (value instanceof CharSequence) {
2195            charSequence = (CharSequence) value;
2196        } else if (value instanceof Reader) {
2197            print((Reader) value, out, newRecord);
2198            return;
2199        } else if (value instanceof InputStream) {
2200            print((InputStream) value, out, newRecord);
2201            return;
2202        } else {
2203            charSequence = value.toString();
2204        }
2205        charSequence = getTrim() ? trim(charSequence) : charSequence;
2206        print(value, charSequence, out, newRecord);
2207    }
2208
2209    private synchronized void print(final Object object, final CharSequence value, final Appendable out, final boolean newRecord) throws IOException {
2210        final int offset = 0;
2211        final int len = value.length();
2212        if (!newRecord) {
2213            out.append(getDelimiterString());
2214        }
2215        if (object == null) {
2216            out.append(value);
2217        } else if (isQuoteCharacterSet()) {
2218            // The original object is needed so can check for Number
2219            printWithQuotes(object, value, out, newRecord);
2220        } else if (isEscapeCharacterSet()) {
2221            printWithEscapes(value, out);
2222        } else {
2223            out.append(value, offset, len);
2224        }
2225    }
2226
2227    /**
2228     * Prints to the specified {@code Path} with given {@code Charset}, returns a {@code CSVPrinter} which the caller MUST close.
2229     *
2230     * <p>
2231     * See also {@link CSVPrinter}.
2232     * </p>
2233     *
2234     * @param out     the output.
2235     * @param charset A charset.
2236     * @return a printer to an output.
2237     * @throws IOException thrown if the optional header cannot be printed.
2238     * @since 1.5
2239     */
2240    @SuppressWarnings("resource")
2241    public CSVPrinter print(final Path out, final Charset charset) throws IOException {
2242        return print(Files.newBufferedWriter(out, charset));
2243    }
2244
2245    private void print(final Reader reader, final Appendable out, final boolean newRecord) throws IOException {
2246        // Reader is never null here
2247        if (!newRecord) {
2248            append(getDelimiterString(), out);
2249        }
2250        if (isQuoteCharacterSet()) {
2251            printWithQuotes(reader, out);
2252        } else if (isEscapeCharacterSet()) {
2253            printWithEscapes(reader, out);
2254        } else if (out instanceof Writer) {
2255            IOUtils.copyLarge(reader, (Writer) out);
2256        } else {
2257            IOUtils.copy(reader, out);
2258        }
2259    }
2260
2261    /**
2262     * Prints to the {@link System#out}.
2263     *
2264     * <p>
2265     * See also {@link CSVPrinter}.
2266     * </p>
2267     *
2268     * @return a printer to {@link System#out}.
2269     * @throws IOException thrown if the optional header cannot be printed.
2270     * @since 1.5
2271     */
2272    public CSVPrinter printer() throws IOException {
2273        return new CSVPrinter(System.out, this);
2274    }
2275
2276    /**
2277     * Outputs the trailing delimiter (if set) followed by the record separator (if set).
2278     *
2279     * @param appendable where to write
2280     * @throws IOException If an I/O error occurs.
2281     * @since 1.4
2282     */
2283    public synchronized void println(final Appendable appendable) throws IOException {
2284        if (getTrailingDelimiter()) {
2285            append(getDelimiterString(), appendable);
2286        }
2287        if (recordSeparator != null) {
2288            append(recordSeparator, appendable);
2289        }
2290    }
2291
2292    /**
2293     * Prints the given {@code values} to {@code out} as a single record of delimiter-separated values followed by the record separator.
2294     *
2295     * <p>
2296     * The values will be quoted if needed. Quotes and new-line characters will be escaped. This method adds the record separator to the output after printing
2297     * the record, so there is no need to call {@link #println(Appendable)}.
2298     * </p>
2299     *
2300     * @param appendable where to write.
2301     * @param values     values to output.
2302     * @throws IOException If an I/O error occurs.
2303     * @since 1.4
2304     */
2305    public synchronized void printRecord(final Appendable appendable, final Object... values) throws IOException {
2306        for (int i = 0; i < values.length; i++) {
2307            print(values[i], appendable, i == 0);
2308        }
2309        println(appendable);
2310    }
2311
2312    /*
2313     * This method must only be called if escaping is enabled, otherwise can throw exceptions.
2314     */
2315    private void printWithEscapes(final CharSequence charSeq, final Appendable appendable) throws IOException {
2316        int start = 0;
2317        int pos = 0;
2318        final int end = charSeq.length();
2319        final char[] delimArray = getDelimiterCharArray();
2320        final int delimLength = delimArray.length;
2321        final char escape = getEscapeChar();
2322        while (pos < end) {
2323            char c = charSeq.charAt(pos);
2324            final boolean isDelimiterStart = isDelimiter(c, charSeq, pos, delimArray, delimLength);
2325            final boolean isCr = c == Constants.CR;
2326            final boolean isLf = c == Constants.LF;
2327            if (isCr || isLf || c == escape || isDelimiterStart) {
2328                // write out segment up until this char
2329                if (pos > start) {
2330                    appendable.append(charSeq, start, pos);
2331                }
2332                if (isLf) {
2333                    c = 'n';
2334                } else if (isCr) {
2335                    c = 'r';
2336                }
2337                escape(c, appendable);
2338                if (isDelimiterStart) {
2339                    for (int i = 1; i < delimLength; i++) {
2340                        pos++;
2341                        escape(charSeq.charAt(pos), appendable);
2342                    }
2343                }
2344                start = pos + 1; // start on the current char after this one
2345            }
2346            pos++;
2347        }
2348
2349        // write last segment
2350        if (pos > start) {
2351            appendable.append(charSeq, start, pos);
2352        }
2353    }
2354
2355    /*
2356     * This method must only be called if escaping is enabled, otherwise can throw exceptions.
2357     */
2358    private void printWithEscapes(final Reader reader, final Appendable appendable) throws IOException {
2359        int start = 0;
2360        int pos = 0;
2361        @SuppressWarnings("resource") // Temp reader on input reader.
2362        final ExtendedBufferedReader bufferedReader = new ExtendedBufferedReader(reader);
2363        final char[] delimArray = getDelimiterCharArray();
2364        final int delimLength = delimArray.length;
2365        final char escape = getEscapeChar();
2366        final StringBuilder builder = new StringBuilder(IOUtils.DEFAULT_BUFFER_SIZE);
2367        int c;
2368        final char[] lookAheadBuffer = new char[delimLength - 1];
2369        while (EOF != (c = bufferedReader.read())) {
2370            builder.append((char) c);
2371            Arrays.fill(lookAheadBuffer, (char) 0);
2372            bufferedReader.peek(lookAheadBuffer);
2373            final String test = builder.toString() + new String(lookAheadBuffer);
2374            final boolean isDelimiterStart = isDelimiter((char) c, test, pos, delimArray, delimLength);
2375            final boolean isCr = c == Constants.CR;
2376            final boolean isLf = c == Constants.LF;
2377            if (isCr || isLf || c == escape || isDelimiterStart) {
2378                // write out segment up until this char
2379                if (pos > start) {
2380                    append(builder.substring(start, pos), appendable);
2381                    builder.setLength(0);
2382                    pos = -1;
2383                }
2384                if (isLf) {
2385                    c = 'n';
2386                } else if (isCr) {
2387                    c = 'r';
2388                }
2389                escape((char) c, appendable);
2390                if (isDelimiterStart) {
2391                    for (int i = 1; i < delimLength; i++) {
2392                        escape((char) bufferedReader.read(), appendable);
2393                    }
2394                }
2395                start = pos + 1; // start on the current char after this one
2396            }
2397            pos++;
2398        }
2399        // write last segment
2400        if (pos > start) {
2401            appendable.append(builder, start, pos);
2402        }
2403    }
2404
2405    /*
2406     * This method must only be called if quoting is enabled, otherwise will generate NPE.
2407     * The original object is needed so can check for Number
2408     */
2409    private void printWithQuotes(final Object object, final CharSequence charSeq, final Appendable out, final boolean newRecord) throws IOException {
2410        boolean quote = false;
2411        int start = 0;
2412        int pos = 0;
2413        final int len = charSeq.length();
2414        final char[] delim = getDelimiterCharArray();
2415        final int delimLength = delim.length;
2416        final char quoteChar = getQuoteCharacter().charValue(); // Explicit (un)boxing is intentional
2417        // If escape char not specified, default to the quote char
2418        // This avoids having to keep checking whether there is an escape character
2419        // at the cost of checking against quote twice
2420        final char escapeChar = isEscapeCharacterSet() ? getEscapeChar() : quoteChar;
2421        QuoteMode quoteModePolicy = getQuoteMode();
2422        if (quoteModePolicy == null) {
2423            quoteModePolicy = QuoteMode.MINIMAL;
2424        }
2425        switch (quoteModePolicy) {
2426        case ALL:
2427        case ALL_NON_NULL:
2428            quote = true;
2429            break;
2430        case NON_NUMERIC:
2431            quote = !(object instanceof Number);
2432            break;
2433        case NONE:
2434            // Use the existing escaping code
2435            printWithEscapes(charSeq, out);
2436            return;
2437        case MINIMAL:
2438            if (len <= 0) {
2439                // Always quote an empty token that is the first
2440                // on the line, as it may be the only thing on the
2441                // line. If it were not quoted in that case,
2442                // an empty line has no tokens.
2443                if (newRecord) {
2444                    quote = true;
2445                }
2446            } else {
2447                char c = charSeq.charAt(pos);
2448                if (c <= Constants.COMMENT) {
2449                    // Some other chars at the start of a value caused the parser to fail, so for now
2450                    // encapsulate if we start in anything less than '#'. We are being conservative
2451                    // by including the default comment char too.
2452                    quote = true;
2453                } else {
2454                    while (pos < len) {
2455                        c = charSeq.charAt(pos);
2456                        if (c == Constants.LF || c == Constants.CR || c == quoteChar || c == escapeChar || isDelimiter(c, charSeq, pos, delim, delimLength)) {
2457                            quote = true;
2458                            break;
2459                        }
2460                        pos++;
2461                    }
2462
2463                    if (!quote) {
2464                        pos = len - 1;
2465                        c = charSeq.charAt(pos);
2466                        // Some other chars at the end caused the parser to fail, so for now
2467                        // encapsulate if we end in anything less than ' '
2468                        if (isTrimChar(c)) {
2469                            quote = true;
2470                        }
2471                    }
2472                }
2473            }
2474            if (!quote) {
2475                // No encapsulation needed - write out the original value
2476                out.append(charSeq, start, len);
2477                return;
2478            }
2479            break;
2480        default:
2481            throw new IllegalStateException("Unexpected Quote value: " + quoteModePolicy);
2482        }
2483        if (!quote) {
2484            // No encapsulation needed - write out the original value
2485            out.append(charSeq, start, len);
2486            return;
2487        }
2488        // We hit something that needed encapsulation
2489        out.append(quoteChar);
2490        // Pick up where we left off: pos should be positioned on the first character that caused
2491        // the need for encapsulation.
2492        while (pos < len) {
2493            final char c = charSeq.charAt(pos);
2494            if (c == quoteChar || c == escapeChar) {
2495                // write out the chunk up until this point
2496                out.append(charSeq, start, pos);
2497                out.append(escapeChar); // now output the escape
2498                start = pos; // and restart with the matched char
2499            }
2500            pos++;
2501        }
2502        // Write the last segment
2503        out.append(charSeq, start, pos);
2504        out.append(quoteChar);
2505    }
2506
2507    /**
2508     * Always use quotes unless QuoteMode is NONE, so we do not have to look ahead.
2509     *
2510     * @param reader     What to print
2511     * @param appendable Where to print it
2512     * @throws IOException If an I/O error occurs
2513     */
2514    private void printWithQuotes(final Reader reader, final Appendable appendable) throws IOException {
2515        if (getQuoteMode() == QuoteMode.NONE) {
2516            printWithEscapes(reader, appendable);
2517            return;
2518        }
2519        final char quote = getQuoteCharacter().charValue(); // Explicit (un)boxing is intentional
2520        // (1) Append opening quote
2521        append(quote, appendable);
2522        // (2) Append Reader contents, doubling quotes
2523        int c;
2524        while (EOF != (c = reader.read())) {
2525            append((char) c, appendable);
2526            if (c == quote) {
2527                append(quote, appendable);
2528            }
2529        }
2530        // (3) Append closing quote
2531        append(quote, appendable);
2532    }
2533
2534    @Override
2535    public String toString() {
2536        final StringBuilder sb = new StringBuilder();
2537        sb.append("Delimiter=<").append(delimiter).append('>');
2538        if (isEscapeCharacterSet()) {
2539            sb.append(' ');
2540            sb.append("Escape=<").append(escapeCharacter).append('>');
2541        }
2542        if (isQuoteCharacterSet()) {
2543            sb.append(' ');
2544            sb.append("QuoteChar=<").append(quoteCharacter).append('>');
2545        }
2546        if (quoteMode != null) {
2547            sb.append(' ');
2548            sb.append("QuoteMode=<").append(quoteMode).append('>');
2549        }
2550        if (isCommentMarkerSet()) {
2551            sb.append(' ');
2552            sb.append("CommentStart=<").append(commentMarker).append('>');
2553        }
2554        if (isNullStringSet()) {
2555            sb.append(' ');
2556            sb.append("NullString=<").append(nullString).append('>');
2557        }
2558        if (recordSeparator != null) {
2559            sb.append(' ');
2560            sb.append("RecordSeparator=<").append(recordSeparator).append('>');
2561        }
2562        if (getIgnoreEmptyLines()) {
2563            sb.append(" EmptyLines:ignored");
2564        }
2565        if (getIgnoreSurroundingSpaces()) {
2566            sb.append(" SurroundingSpaces:ignored");
2567        }
2568        if (getIgnoreHeaderCase()) {
2569            sb.append(" IgnoreHeaderCase:ignored");
2570        }
2571        sb.append(" SkipHeaderRecord:").append(skipHeaderRecord);
2572        if (headerComments != null) {
2573            sb.append(' ');
2574            sb.append("HeaderComments:").append(Arrays.toString(headerComments));
2575        }
2576        if (headers != null) {
2577            sb.append(' ');
2578            sb.append("Header:").append(Arrays.toString(headers));
2579        }
2580        return sb.toString();
2581    }
2582
2583    String trim(final String value) {
2584        return getTrim() ? value.trim() : value;
2585    }
2586
2587    boolean useMaxRows() {
2588        return getMaxRows() > 0;
2589    }
2590
2591    boolean useRow(final long rowNum) {
2592        return !useMaxRows() || rowNum <= getMaxRows();
2593    }
2594
2595    /**
2596     * Verifies the validity and consistency of the attributes, and throws an {@link IllegalArgumentException} if necessary.
2597     * <p>
2598     * Because an instance can be used for both writing and parsing, not all conditions can be tested here. For example, allowMissingColumnNames is only used
2599     * for parsing, so it cannot be used here.
2600     * </p>
2601     *
2602     * @throws IllegalArgumentException Throw when any attribute is invalid or inconsistent with other attributes.
2603     */
2604    private void validate() throws IllegalArgumentException {
2605        if (quoteCharacter != null && contains(delimiter, quoteCharacter.charValue())) { // Explicit (un)boxing is intentional
2606            throw new IllegalArgumentException("The quoteChar character and the delimiter cannot be the same ('" + quoteCharacter + "')");
2607        }
2608        if (escapeCharacter != null && contains(delimiter, escapeCharacter.charValue())) { // Explicit (un)boxing is intentional
2609            throw new IllegalArgumentException("The escape character and the delimiter cannot be the same ('" + escapeCharacter + "')");
2610        }
2611        if (commentMarker != null && contains(delimiter, commentMarker.charValue())) { // Explicit (un)boxing is intentional
2612            throw new IllegalArgumentException("The comment start character and the delimiter cannot be the same ('" + commentMarker + "')");
2613        }
2614        if (quoteCharacter != null && quoteCharacter.equals(commentMarker)) {
2615            throw new IllegalArgumentException("The comment start character and the quoteChar cannot be the same ('" + commentMarker + "')");
2616        }
2617        if (escapeCharacter != null && escapeCharacter.equals(commentMarker)) {
2618            throw new IllegalArgumentException("The comment start and the escape character cannot be the same ('" + commentMarker + "')");
2619        }
2620        if (escapeCharacter == null && quoteMode == QuoteMode.NONE) {
2621            throw new IllegalArgumentException("Quote mode set to NONE but no escape character is set");
2622        }
2623        // Validate headers
2624        if (headers != null && duplicateHeaderMode != DuplicateHeaderMode.ALLOW_ALL) {
2625            final Set<String> dupCheckSet = new HashSet<>(headers.length);
2626            final boolean emptyDuplicatesAllowed = duplicateHeaderMode == DuplicateHeaderMode.ALLOW_EMPTY;
2627            for (final String header : headers) {
2628                final boolean blank = isBlank(header);
2629                // Sanitize all empty headers to the empty string "" when checking duplicates
2630                final boolean containsHeader = !dupCheckSet.add(blank ? "" : header);
2631                if (containsHeader && !(blank && emptyDuplicatesAllowed)) {
2632                    throw new IllegalArgumentException(String.format(
2633                            "The header contains a duplicate name: \"%s\" in %s. If this is valid then use CSVFormat.Builder.setDuplicateHeaderMode().", header,
2634                            Arrays.toString(headers)));
2635                }
2636            }
2637        }
2638    }
2639
2640    /**
2641     * Builds a new {@code CSVFormat} that allows duplicate header names.
2642     *
2643     * @return a new {@code CSVFormat} that allows duplicate header names
2644     * @since 1.7
2645     * @deprecated Use {@link Builder#setAllowDuplicateHeaderNames(boolean) Builder#setAllowDuplicateHeaderNames(true)}
2646     */
2647    @Deprecated
2648    public CSVFormat withAllowDuplicateHeaderNames() {
2649        return builder().setDuplicateHeaderMode(DuplicateHeaderMode.ALLOW_ALL).get();
2650    }
2651
2652    /**
2653     * Builds a new {@code CSVFormat} with duplicate header names behavior set to the given value.
2654     *
2655     * @param allowDuplicateHeaderNames the duplicate header names behavior, true to allow, false to disallow.
2656     * @return a new {@code CSVFormat} with duplicate header names behavior set to the given value.
2657     * @since 1.7
2658     * @deprecated Use {@link Builder#setAllowDuplicateHeaderNames(boolean)}
2659     */
2660    @Deprecated
2661    public CSVFormat withAllowDuplicateHeaderNames(final boolean allowDuplicateHeaderNames) {
2662        final DuplicateHeaderMode mode = allowDuplicateHeaderNames ? DuplicateHeaderMode.ALLOW_ALL : DuplicateHeaderMode.ALLOW_EMPTY;
2663        return builder().setDuplicateHeaderMode(mode).get();
2664    }
2665
2666    /**
2667     * Builds a new {@code CSVFormat} with the missing column names behavior of the format set to {@code true}.
2668     *
2669     * @return A new CSVFormat that is equal to this but with the specified missing column names behavior.
2670     * @see Builder#setAllowMissingColumnNames(boolean)
2671     * @since 1.1
2672     * @deprecated Use {@link Builder#setAllowMissingColumnNames(boolean) Builder#setAllowMissingColumnNames(true)}
2673     */
2674    @Deprecated
2675    public CSVFormat withAllowMissingColumnNames() {
2676        return builder().setAllowMissingColumnNames(true).get();
2677    }
2678
2679    /**
2680     * Builds a new {@code CSVFormat} with the missing column names behavior of the format set to the given value.
2681     *
2682     * @param allowMissingColumnNames the missing column names behavior, {@code true} to allow missing column names in the header line, {@code false} to cause
2683     *                                an {@link IllegalArgumentException} to be thrown.
2684     * @return A new CSVFormat that is equal to this but with the specified missing column names behavior.
2685     * @deprecated Use {@link Builder#setAllowMissingColumnNames(boolean)}
2686     */
2687    @Deprecated
2688    public CSVFormat withAllowMissingColumnNames(final boolean allowMissingColumnNames) {
2689        return builder().setAllowMissingColumnNames(allowMissingColumnNames).get();
2690    }
2691
2692    /**
2693     * Builds a new {@code CSVFormat} with whether to flush on close.
2694     *
2695     * @param autoFlush whether to flush on close.
2696     * @return A new CSVFormat that is equal to this but with the specified autoFlush setting.
2697     * @since 1.6
2698     * @deprecated Use {@link Builder#setAutoFlush(boolean)}
2699     */
2700    @Deprecated
2701    public CSVFormat withAutoFlush(final boolean autoFlush) {
2702        return builder().setAutoFlush(autoFlush).get();
2703    }
2704
2705    /**
2706     * Builds a new {@code CSVFormat} with the comment start marker of the format set to the specified character.
2707     *
2708     * Note that the comment start character is only recognized at the start of a line.
2709     *
2710     * @param commentMarker the comment start marker
2711     * @return A new CSVFormat that is equal to this one but with the specified character as the comment start marker
2712     * @throws IllegalArgumentException thrown if the specified character is a line break
2713     * @deprecated Use {@link Builder#setCommentMarker(char)}
2714     */
2715    @Deprecated
2716    public CSVFormat withCommentMarker(final char commentMarker) {
2717        return builder().setCommentMarker(commentMarker).get();
2718    }
2719
2720    /**
2721     * Builds a new {@code CSVFormat} with the comment start marker of the format set to the specified character.
2722     *
2723     * Note that the comment start character is only recognized at the start of a line.
2724     *
2725     * @param commentMarker the comment start marker, use {@code null} to disable
2726     * @return A new CSVFormat that is equal to this one but with the specified character as the comment start marker
2727     * @throws IllegalArgumentException thrown if the specified character is a line break
2728     * @deprecated Use {@link Builder#setCommentMarker(Character)}
2729     */
2730    @Deprecated
2731    public CSVFormat withCommentMarker(final Character commentMarker) {
2732        return builder().setCommentMarker(commentMarker).get();
2733    }
2734
2735    /**
2736     * Builds a new {@code CSVFormat} with the delimiter of the format set to the specified character.
2737     *
2738     * @param delimiter the delimiter character
2739     * @return A new CSVFormat that is equal to this with the specified character as a delimiter
2740     * @throws IllegalArgumentException thrown if the specified character is a line break
2741     * @deprecated Use {@link Builder#setDelimiter(char)}
2742     */
2743    @Deprecated
2744    public CSVFormat withDelimiter(final char delimiter) {
2745        return builder().setDelimiter(delimiter).get();
2746    }
2747
2748    /**
2749     * Builds a new {@code CSVFormat} with the escape character of the format set to the specified character.
2750     *
2751     * @param escape the escape character
2752     * @return A new CSVFormat that is equal to this but with the specified character as the escape character
2753     * @throws IllegalArgumentException thrown if the specified character is a line break
2754     * @deprecated Use {@link Builder#setEscape(char)}
2755     */
2756    @Deprecated
2757    public CSVFormat withEscape(final char escape) {
2758        return builder().setEscape(escape).get();
2759    }
2760
2761    /**
2762     * Builds a new {@code CSVFormat} with the escape character of the format set to the specified character.
2763     *
2764     * @param escape the escape character, use {@code null} to disable
2765     * @return A new CSVFormat that is equal to this but with the specified character as the escape character
2766     * @throws IllegalArgumentException thrown if the specified character is a line break
2767     * @deprecated Use {@link Builder#setEscape(Character)}
2768     */
2769    @Deprecated
2770    public CSVFormat withEscape(final Character escape) {
2771        return builder().setEscape(escape).get();
2772    }
2773
2774    // @formatter:off
2775    /**
2776     * Builds a new {@code CSVFormat} using the first record as header.
2777     *
2778     * <p>
2779     * Calling this method is equivalent to calling:
2780     * </p>
2781     *
2782     * <pre>
2783     * CSVFormat format = aFormat.builder()
2784     *                           .setHeader()
2785     *                           .setSkipHeaderRecord(true)
2786     *                           .get();
2787     * </pre>
2788     *
2789     * @return A new CSVFormat that is equal to this but using the first record as header.
2790     * @see Builder#setSkipHeaderRecord(boolean)
2791     * @see Builder#setHeader(String...)
2792     * @since 1.3
2793     * @deprecated Use {@link Builder#setHeader(String...) Builder#setHeader()}.{@link Builder#setSkipHeaderRecord(boolean) setSkipHeaderRecord(true)}.
2794     */
2795    // @formatter:on
2796    @Deprecated
2797    public CSVFormat withFirstRecordAsHeader() {
2798        // @formatter:off
2799        return builder()
2800                .setHeader()
2801                .setSkipHeaderRecord(true)
2802                .get();
2803        // @formatter:on
2804    }
2805
2806    /**
2807     * Builds a new {@code CSVFormat} with the header of the format defined by the enum class.
2808     *
2809     * <p>
2810     * Example:
2811     * </p>
2812     *
2813     * <pre>
2814     * public enum MyHeader {
2815     *     Name, Email, Phone
2816     * }
2817     * ...
2818     * CSVFormat format = aFormat.builder().setHeader(MyHeader.class).get();
2819     * </pre>
2820     * <p>
2821     * The header is also used by the {@link CSVPrinter}.
2822     * </p>
2823     *
2824     * @param headerEnum the enum defining the header, {@code null} if disabled, empty if parsed automatically, user specified otherwise.
2825     * @return A new CSVFormat that is equal to this but with the specified header
2826     * @see Builder#setHeader(String...)
2827     * @see Builder#setSkipHeaderRecord(boolean)
2828     * @since 1.3
2829     * @deprecated Use {@link Builder#setHeader(Class)}
2830     */
2831    @Deprecated
2832    public CSVFormat withHeader(final Class<? extends Enum<?>> headerEnum) {
2833        return builder().setHeader(headerEnum).get();
2834    }
2835
2836    /**
2837     * Builds a new {@code CSVFormat} with the header of the format set from the result set metadata. The header can either be parsed automatically from the
2838     * input file with:
2839     *
2840     * <pre>
2841     * CSVFormat format = aFormat.builder().setHeader().get();
2842     * </pre>
2843     *
2844     * or specified manually with:
2845     *
2846     * <pre>
2847     * CSVFormat format = aFormat.builder().setHeader(resultSet).get();
2848     * </pre>
2849     * <p>
2850     * The header is also used by the {@link CSVPrinter}.
2851     * </p>
2852     *
2853     * @param resultSet the resultSet for the header, {@code null} if disabled, empty if parsed automatically, user-specified otherwise.
2854     * @return A new CSVFormat that is equal to this but with the specified header
2855     * @throws SQLException SQLException if a database access error occurs or this method is called on a closed result set.
2856     * @since 1.1
2857     * @deprecated Use {@link Builder#setHeader(ResultSet)}
2858     */
2859    @Deprecated
2860    public CSVFormat withHeader(final ResultSet resultSet) throws SQLException {
2861        return builder().setHeader(resultSet).get();
2862    }
2863
2864    /**
2865     * Builds a new {@code CSVFormat} with the header of the format set from the result set metadata. The header can either be parsed automatically from the
2866     * input file with:
2867     *
2868     * <pre>
2869     * CSVFormat format = aFormat.builder().setHeader().get()
2870     * </pre>
2871     *
2872     * or specified manually with:
2873     *
2874     * <pre>
2875     * CSVFormat format = aFormat.builder().setHeader(resultSetMetaData).get()
2876     * </pre>
2877     * <p>
2878     * The header is also used by the {@link CSVPrinter}.
2879     * </p>
2880     *
2881     * @param resultSetMetaData the metaData for the header, {@code null} if disabled, empty if parsed automatically, user specified otherwise.
2882     * @return A new CSVFormat that is equal to this but with the specified header
2883     * @throws SQLException SQLException if a database access error occurs or this method is called on a closed result set.
2884     * @since 1.1
2885     * @deprecated Use {@link Builder#setHeader(ResultSetMetaData)}
2886     */
2887    @Deprecated
2888    public CSVFormat withHeader(final ResultSetMetaData resultSetMetaData) throws SQLException {
2889        return builder().setHeader(resultSetMetaData).get();
2890    }
2891
2892    /**
2893     * Builds a new {@code CSVFormat} with the header of the format set to the given values. The header can either be parsed automatically from the input file
2894     * with:
2895     *
2896     * <pre>
2897     * CSVFormat format = aFormat.builder().setHeader().get();
2898     * </pre>
2899     *
2900     * or specified manually with:
2901     *
2902     * <pre>{@code
2903     * CSVFormat format = aFormat.builder().setHeader("name", "email", "phone").get();
2904     * }</pre>
2905     * <p>
2906     * The header is also used by the {@link CSVPrinter}.
2907     * </p>
2908     *
2909     * @param header the header, {@code null} if disabled, empty if parsed automatically, user-specified otherwise.
2910     * @return A new CSVFormat that is equal to this but with the specified header
2911     * @see Builder#setSkipHeaderRecord(boolean)
2912     * @deprecated Use {@link Builder#setHeader(String...)}
2913     */
2914    @Deprecated
2915    public CSVFormat withHeader(final String... header) {
2916        return builder().setHeader(header).get();
2917    }
2918
2919    /**
2920     * Builds a new {@code CSVFormat} with the header comments of the format set to the given values. The comments will be printed first, before the headers.
2921     * This setting is ignored by the parser.
2922     *
2923     * <pre>{@code
2924     * CSVFormat format = aFormat.builder().setHeaderComments("Generated by Apache Commons CSV.", Instant.now()).get();
2925     * }</pre>
2926     *
2927     * @param headerComments the headerComments which will be printed by the Printer before the actual CSV data.
2928     * @return A new CSVFormat that is equal to this but with the specified header
2929     * @see Builder#setSkipHeaderRecord(boolean)
2930     * @since 1.1
2931     * @deprecated Use {@link Builder#setHeaderComments(Object...)}
2932     */
2933    @Deprecated
2934    public CSVFormat withHeaderComments(final Object... headerComments) {
2935        return builder().setHeaderComments(headerComments).get();
2936    }
2937
2938    /**
2939     * Builds a new {@code CSVFormat} with the empty line skipping behavior of the format set to {@code true}.
2940     *
2941     * @return A new CSVFormat that is equal to this but with the specified empty line skipping behavior.
2942     * @see Builder#setIgnoreEmptyLines(boolean)
2943     * @since 1.1
2944     * @deprecated Use {@link Builder#setIgnoreEmptyLines(boolean) Builder#setIgnoreEmptyLines(true)}
2945     */
2946    @Deprecated
2947    public CSVFormat withIgnoreEmptyLines() {
2948        return builder().setIgnoreEmptyLines(true).get();
2949    }
2950
2951    /**
2952     * Builds a new {@code CSVFormat} with the empty line skipping behavior of the format set to the given value.
2953     *
2954     * @param ignoreEmptyLines the empty line skipping behavior, {@code true} to ignore the empty lines between the records, {@code false} to translate empty
2955     *                         lines to empty records.
2956     * @return A new CSVFormat that is equal to this but with the specified empty line skipping behavior.
2957     * @deprecated Use {@link Builder#setIgnoreEmptyLines(boolean)}
2958     */
2959    @Deprecated
2960    public CSVFormat withIgnoreEmptyLines(final boolean ignoreEmptyLines) {
2961        return builder().setIgnoreEmptyLines(ignoreEmptyLines).get();
2962    }
2963
2964    /**
2965     * Builds a new {@code CSVFormat} with the header ignore case behavior set to {@code true}.
2966     *
2967     * @return A new CSVFormat that will ignore the new case header name behavior.
2968     * @see Builder#setIgnoreHeaderCase(boolean)
2969     * @since 1.3
2970     * @deprecated Use {@link Builder#setIgnoreHeaderCase(boolean) Builder#setIgnoreHeaderCase(true)}
2971     */
2972    @Deprecated
2973    public CSVFormat withIgnoreHeaderCase() {
2974        return builder().setIgnoreHeaderCase(true).get();
2975    }
2976
2977    /**
2978     * Builds a new {@code CSVFormat} with whether header names should be accessed ignoring case.
2979     *
2980     * @param ignoreHeaderCase the case mapping behavior, {@code true} to access name/values, {@code false} to leave the mapping as is.
2981     * @return A new CSVFormat that will ignore case header name if specified as {@code true}
2982     * @since 1.3
2983     * @deprecated Use {@link Builder#setIgnoreHeaderCase(boolean)}
2984     */
2985    @Deprecated
2986    public CSVFormat withIgnoreHeaderCase(final boolean ignoreHeaderCase) {
2987        return builder().setIgnoreHeaderCase(ignoreHeaderCase).get();
2988    }
2989
2990    /**
2991     * Builds a new {@code CSVFormat} with the parser trimming behavior of the format set to {@code true}.
2992     *
2993     * @return A new CSVFormat that is equal to this but with the specified parser trimming behavior.
2994     * @see Builder#setIgnoreSurroundingSpaces(boolean)
2995     * @since 1.1
2996     * @deprecated Use {@link Builder#setIgnoreSurroundingSpaces(boolean) Builder#setIgnoreSurroundingSpaces(true)}
2997     */
2998    @Deprecated
2999    public CSVFormat withIgnoreSurroundingSpaces() {
3000        return builder().setIgnoreSurroundingSpaces(true).get();
3001    }
3002
3003    /**
3004     * Builds a new {@code CSVFormat} with the parser trimming behavior of the format set to the given value.
3005     *
3006     * @param ignoreSurroundingSpaces the parser trimming behavior, {@code true} to remove the surrounding spaces, {@code false} to leave the spaces as is.
3007     * @return A new CSVFormat that is equal to this but with the specified trimming behavior.
3008     * @deprecated Use {@link Builder#setIgnoreSurroundingSpaces(boolean)}
3009     */
3010    @Deprecated
3011    public CSVFormat withIgnoreSurroundingSpaces(final boolean ignoreSurroundingSpaces) {
3012        return builder().setIgnoreSurroundingSpaces(ignoreSurroundingSpaces).get();
3013    }
3014
3015    /**
3016     * Builds a new {@code CSVFormat} with conversions to and from null for strings on input and output.
3017     * <ul>
3018     * <li><strong>Reading:</strong> Converts strings equal to the given {@code nullString} to {@code null} when reading records.</li>
3019     * <li><strong>Writing:</strong> Writes {@code null} as the given {@code nullString} when writing records.</li>
3020     * </ul>
3021     *
3022     * @param nullString the String to convert to and from {@code null}. No substitution occurs if {@code null}
3023     * @return A new CSVFormat that is equal to this but with the specified null conversion string.
3024     * @deprecated Use {@link Builder#setNullString(String)}
3025     */
3026    @Deprecated
3027    public CSVFormat withNullString(final String nullString) {
3028        return builder().setNullString(nullString).get();
3029    }
3030
3031    /**
3032     * Builds a new {@code CSVFormat} with the quoteChar of the format set to the specified character.
3033     *
3034     * @param quoteChar the quote character
3035     * @return A new CSVFormat that is equal to this but with the specified character as quoteChar
3036     * @throws IllegalArgumentException thrown if the specified character is a line break
3037     * @deprecated Use {@link Builder#setQuote(char)}
3038     */
3039    @Deprecated
3040    public CSVFormat withQuote(final char quoteChar) {
3041        return builder().setQuote(quoteChar).get();
3042    }
3043
3044    /**
3045     * Builds a new {@code CSVFormat} with the quoteChar of the format set to the specified character.
3046     *
3047     * @param quoteChar the quote character, use {@code null} to disable.
3048     * @return A new CSVFormat that is equal to this but with the specified character as quoteChar
3049     * @throws IllegalArgumentException thrown if the specified character is a line break
3050     * @deprecated Use {@link Builder#setQuote(Character)}
3051     */
3052    @Deprecated
3053    public CSVFormat withQuote(final Character quoteChar) {
3054        return builder().setQuote(quoteChar).get();
3055    }
3056
3057    /**
3058     * Builds a new {@code CSVFormat} with the output quote policy of the format set to the specified value.
3059     *
3060     * @param quoteMode the quote policy to use for output.
3061     * @return A new CSVFormat that is equal to this but with the specified quote policy
3062     * @deprecated Use {@link Builder#setQuoteMode(QuoteMode)}
3063     */
3064    @Deprecated
3065    public CSVFormat withQuoteMode(final QuoteMode quoteMode) {
3066        return builder().setQuoteMode(quoteMode).get();
3067    }
3068
3069    /**
3070     * Builds a new {@code CSVFormat} with the record separator of the format set to the specified character.
3071     *
3072     * <p>
3073     * <strong>Note:</strong> This setting is only used during printing and does not affect parsing. Parsing currently only works for inputs with '\n', '\r' and
3074     * "\r\n"
3075     * </p>
3076     *
3077     * @param recordSeparator the record separator to use for output.
3078     * @return A new CSVFormat that is equal to this but with the specified output record separator
3079     * @deprecated Use {@link Builder#setRecordSeparator(char)}
3080     */
3081    @Deprecated
3082    public CSVFormat withRecordSeparator(final char recordSeparator) {
3083        return builder().setRecordSeparator(recordSeparator).get();
3084    }
3085
3086    /**
3087     * Builds a new {@code CSVFormat} with the record separator of the format set to the specified String.
3088     *
3089     * <p>
3090     * <strong>Note:</strong> This setting is only used during printing and does not affect parsing. Parsing currently only works for inputs with '\n', '\r' and
3091     * "\r\n"
3092     * </p>
3093     *
3094     * @param recordSeparator the record separator to use for output.
3095     * @return A new CSVFormat that is equal to this but with the specified output record separator
3096     * @throws IllegalArgumentException if recordSeparator is none of CR, LF or CRLF
3097     * @deprecated Use {@link Builder#setRecordSeparator(String)}
3098     */
3099    @Deprecated
3100    public CSVFormat withRecordSeparator(final String recordSeparator) {
3101        return builder().setRecordSeparator(recordSeparator).get();
3102    }
3103
3104    /**
3105     * Builds a new {@code CSVFormat} with skipping the header record set to {@code true}.
3106     *
3107     * @return A new CSVFormat that is equal to this but with the specified skipHeaderRecord setting.
3108     * @see Builder#setSkipHeaderRecord(boolean)
3109     * @see Builder#setHeader(String...)
3110     * @since 1.1
3111     * @deprecated Use {@link Builder#setSkipHeaderRecord(boolean) Builder#setSkipHeaderRecord(true)}
3112     */
3113    @Deprecated
3114    public CSVFormat withSkipHeaderRecord() {
3115        return builder().setSkipHeaderRecord(true).get();
3116    }
3117
3118    /**
3119     * Builds a new {@code CSVFormat} with whether to skip the header record.
3120     *
3121     * @param skipHeaderRecord whether to skip the header record.
3122     * @return A new CSVFormat that is equal to this but with the specified skipHeaderRecord setting.
3123     * @see Builder#setHeader(String...)
3124     * @deprecated Use {@link Builder#setSkipHeaderRecord(boolean)}
3125     */
3126    @Deprecated
3127    public CSVFormat withSkipHeaderRecord(final boolean skipHeaderRecord) {
3128        return builder().setSkipHeaderRecord(skipHeaderRecord).get();
3129    }
3130
3131    /**
3132     * Builds a new {@code CSVFormat} with the record separator of the format set to the operating system's line separator string, typically CR+LF on Windows
3133     * and LF on Linux.
3134     *
3135     * <p>
3136     * <strong>Note:</strong> This setting is only used during printing and does not affect parsing. Parsing currently only works for inputs with '\n', '\r' and
3137     * "\r\n"
3138     * </p>
3139     *
3140     * @return A new CSVFormat that is equal to this but with the operating system's line separator string.
3141     * @since 1.6
3142     * @deprecated Use {@link Builder#setRecordSeparator(String) setRecordSeparator(System.lineSeparator())}
3143     */
3144    @Deprecated
3145    public CSVFormat withSystemRecordSeparator() {
3146        return builder().setRecordSeparator(System.lineSeparator()).get();
3147    }
3148
3149    /**
3150     * Builds a new {@code CSVFormat} to add a trailing delimiter.
3151     *
3152     * @return A new CSVFormat that is equal to this but with the trailing delimiter setting.
3153     * @since 1.3
3154     * @deprecated Use {@link Builder#setTrailingDelimiter(boolean) Builder#setTrailingDelimiter(true)}
3155     */
3156    @Deprecated
3157    public CSVFormat withTrailingDelimiter() {
3158        return builder().setTrailingDelimiter(true).get();
3159    }
3160
3161    /**
3162     * Builds a new {@code CSVFormat} with whether to add a trailing delimiter.
3163     *
3164     * @param trailingDelimiter whether to add a trailing delimiter.
3165     * @return A new CSVFormat that is equal to this but with the specified trailing delimiter setting.
3166     * @since 1.3
3167     * @deprecated Use {@link Builder#setTrailingDelimiter(boolean)}
3168     */
3169    @Deprecated
3170    public CSVFormat withTrailingDelimiter(final boolean trailingDelimiter) {
3171        return builder().setTrailingDelimiter(trailingDelimiter).get();
3172    }
3173
3174    /**
3175     * Builds a new {@code CSVFormat} to trim leading and trailing blanks. See {@link #getTrim()} for details of where this is used.
3176     *
3177     * @return A new CSVFormat that is equal to this but with the trim setting on.
3178     * @since 1.3
3179     * @deprecated Use {@link Builder#setTrim(boolean) Builder#setTrim(true)}
3180     */
3181    @Deprecated
3182    public CSVFormat withTrim() {
3183        return builder().setTrim(true).get();
3184    }
3185
3186    /**
3187     * Builds a new {@code CSVFormat} with whether to trim leading and trailing blanks. See {@link #getTrim()} for details of where this is used.
3188     *
3189     * @param trim whether to trim leading and trailing blanks.
3190     * @return A new CSVFormat that is equal to this but with the specified trim setting.
3191     * @since 1.3
3192     * @deprecated Use {@link Builder#setTrim(boolean)}
3193     */
3194    @Deprecated
3195    public CSVFormat withTrim(final boolean trim) {
3196        return builder().setTrim(trim).get();
3197    }
3198
3199}