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