CSVFormat.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one
  3.  * or more contributor license agreements.  See the NOTICE file
  4.  * distributed with this work for additional information
  5.  * regarding copyright ownership.  The ASF licenses this file
  6.  * to you under the Apache License, Version 2.0 (the
  7.  * "License"); you may not use this file except in compliance
  8.  * with the License.  You may obtain a copy of the License at
  9.  *
  10.  *   https://www.apache.org/licenses/LICENSE-2.0
  11.  *
  12.  * Unless required by applicable law or agreed to in writing,
  13.  * software distributed under the License is distributed on an
  14.  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15.  * KIND, either express or implied.  See the License for the
  16.  * specific language governing permissions and limitations
  17.  * under the License.
  18.  */

  19. package org.apache.commons.csv;

  20. import static org.apache.commons.io.IOUtils.EOF;

  21. import java.io.File;
  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.io.OutputStream;
  25. import java.io.Reader;
  26. import java.io.Serializable;
  27. import java.io.StringWriter;
  28. import java.io.Writer;
  29. import java.nio.charset.Charset;
  30. import java.nio.file.Files;
  31. import java.nio.file.Path;
  32. import java.sql.ResultSet;
  33. import java.sql.ResultSetMetaData;
  34. import java.sql.SQLException;
  35. import java.util.Arrays;
  36. import java.util.HashSet;
  37. import java.util.Objects;
  38. import java.util.Set;
  39. import java.util.function.Supplier;

  40. import org.apache.commons.codec.binary.Base64OutputStream;
  41. import org.apache.commons.io.IOUtils;
  42. import org.apache.commons.io.function.IOStream;
  43. import org.apache.commons.io.function.Uncheck;
  44. import org.apache.commons.io.output.AppendableOutputStream;

  45. /**
  46.  * Specifies the format of a CSV file for parsing and writing.
  47.  *
  48.  * <h2>Using predefined formats</h2>
  49.  *
  50.  * <p>
  51.  * You can use one of the predefined formats:
  52.  * </p>
  53.  *
  54.  * <ul>
  55.  * <li>{@link #DEFAULT}</li>
  56.  * <li>{@link #EXCEL}</li>
  57.  * <li>{@link #INFORMIX_UNLOAD}</li>
  58.  * <li>{@link #INFORMIX_UNLOAD_CSV}</li>
  59.  * <li>{@link #MONGODB_CSV}</li>
  60.  * <li>{@link #MONGODB_TSV}</li>
  61.  * <li>{@link #MYSQL}</li>
  62.  * <li>{@link #ORACLE}</li>
  63.  * <li>{@link #POSTGRESQL_CSV}</li>
  64.  * <li>{@link #POSTGRESQL_TEXT}</li>
  65.  * <li>{@link #RFC4180}</li>
  66.  * <li>{@link #TDF}</li>
  67.  * </ul>
  68.  *
  69.  * <p>
  70.  * For example:
  71.  * </p>
  72.  *
  73.  * <pre>
  74.  * CSVParser parser = CSVFormat.EXCEL.parse(reader);
  75.  * </pre>
  76.  *
  77.  * <p>
  78.  * The {@link CSVParser} provides static methods to parse other input types, for example:
  79.  * </p>
  80.  *
  81.  * <pre>
  82.  * CSVParser parser = CSVParser.parse(file, StandardCharsets.US_ASCII, CSVFormat.EXCEL);
  83.  * </pre>
  84.  *
  85.  * <h2>Defining formats</h2>
  86.  *
  87.  * <p>
  88.  * You can extend a format by calling the {@code set} methods. For example:
  89.  * </p>
  90.  *
  91.  * <pre>{@code
  92.  * CSVFormat.EXCEL.builder().setNullString("N/A").setIgnoreSurroundingSpaces(true).get();
  93.  * }</pre>
  94.  *
  95.  * <h2>Defining column names</h2>
  96.  *
  97.  * <p>
  98.  * To define the column names you want to use to access records, write:
  99.  * </p>
  100.  *
  101.  * <pre>{@code
  102.  * CSVFormat.EXCEL.builder().setHeader("Col1", "Col2", "Col3").get();
  103.  * }</pre>
  104.  *
  105.  * <p>
  106.  * 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
  107.  * contain a first record that also defines column names.
  108.  *
  109.  * If it does, then you are overriding this metadata with your names and you should skip the first record by calling
  110.  * {@link Builder#setSkipHeaderRecord(boolean)} with {@code true}.
  111.  * </p>
  112.  *
  113.  * <h2>Parsing</h2>
  114.  *
  115.  * <p>
  116.  * You can use a format directly to parse a reader. For example, to parse an Excel file with columns header, write:
  117.  * </p>
  118.  *
  119.  * <pre>{@code
  120.  * Reader in = ...;
  121.  * CSVFormat.EXCEL.builder().setHeader("Col1", "Col2", "Col3").get().parse(in);
  122.  * }</pre>
  123.  *
  124.  * <p>
  125.  * For other input types, like resources, files, and URLs, use the static methods on {@link CSVParser}.
  126.  * </p>
  127.  *
  128.  * <h2>Referencing columns safely</h2>
  129.  *
  130.  * <p>
  131.  * If your source contains a header record, you can simplify your code and safely reference columns, by using {@link Builder#setHeader(String...)} with no
  132.  * arguments:
  133.  * </p>
  134.  *
  135.  * <pre>
  136.  * CSVFormat.EXCEL.builder().setHeader().get();
  137.  * </pre>
  138.  *
  139.  * <p>
  140.  * This causes the parser to read the first record and use its values as column names.
  141.  *
  142.  * Then, call one of the {@link CSVRecord} get method that takes a String column name argument:
  143.  * </p>
  144.  *
  145.  * <pre>{@code
  146.  * String value = record.get("Col1");
  147.  * }</pre>
  148.  *
  149.  * <p>
  150.  * This makes your code impervious to changes in column order in the CSV file.
  151.  * </p>
  152.  *
  153.  * <h2>Serialization</h2>
  154.  * <p>
  155.  * This class implements the {@link Serializable} interface with the following caveats:
  156.  * </p>
  157.  * <ul>
  158.  * <li>This class will no longer implement Serializable in 2.0.</li>
  159.  * <li>Serialization is not supported from one version to the next.</li>
  160.  * </ul>
  161.  * <p>
  162.  * The {@code serialVersionUID} values are:
  163.  * </p>
  164.  * <ul>
  165.  * <li>Version 1.10.0: {@code 2L}</li>
  166.  * <li>Version 1.9.0 through 1.0: {@code 1L}</li>
  167.  * </ul>
  168.  *
  169.  * <h2>Notes</h2>
  170.  * <p>
  171.  * This class is immutable.
  172.  * </p>
  173.  * <p>
  174.  * Not all settings are used for both parsing and writing.
  175.  * </p>
  176.  */
  177. public final class CSVFormat implements Serializable {

  178.     /**
  179.      * Builds CSVFormat instances.
  180.      *
  181.      * @since 1.9.0
  182.      */
  183.     public static class Builder implements Supplier<CSVFormat> {

  184.         /**
  185.          * Creates a new default builder, as for {@link #RFC4180} but allowing empty lines.
  186.          *
  187.          * <p>
  188.          * The {@link Builder} settings are:
  189.          * </p>
  190.          * <ul>
  191.          * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')}</li>
  192.          * <li>{@link Builder#setQuote(char) setQuote}{@code ('"')}</li>
  193.          * <li>{@link Builder#setRecordSeparator(String) setRecordSeparator}{@code ("\r\n")}</li>
  194.          * <li>{@link Builder#setIgnoreEmptyLines(boolean) setIgnoreEmptyLines}{@code (true)}</li>
  195.          * <li>{@link Builder#setDuplicateHeaderMode(DuplicateHeaderMode) setDuplicateHeaderMode}{@code (DuplicateHeaderMode.ALLOW_ALL)}</li>
  196.          * <li>All other values take their Java defaults, {@code false} for booleans, {@code null} for object references.</li>
  197.          * </ul>
  198.          *
  199.          * @see Predefined#Default
  200.          * @see DuplicateHeaderMode#ALLOW_ALL
  201.          *
  202.          * @return a copy of the builder
  203.          */
  204.         public static Builder create() {
  205.             // @formatter:off
  206.             return new Builder()
  207.                     .setDelimiter(Constants.COMMA)
  208.                     .setQuote(Constants.DOUBLE_QUOTE_CHAR)
  209.                     .setRecordSeparator(Constants.CRLF)
  210.                     .setIgnoreEmptyLines(true)
  211.                     .setDuplicateHeaderMode(DuplicateHeaderMode.ALLOW_ALL);
  212.                     // @formatter:on
  213.         }

  214.         /**
  215.          * Creates a new builder from the given format.
  216.          *
  217.          * @param csvFormat the source format.
  218.          * @return a new builder.
  219.          */
  220.         public static Builder create(final CSVFormat csvFormat) {
  221.             return new Builder(csvFormat);
  222.         }

  223.         private boolean allowMissingColumnNames;

  224.         private boolean autoFlush;

  225.         private Character commentMarker;

  226.         private String delimiter;

  227.         private DuplicateHeaderMode duplicateHeaderMode;

  228.         private Character escapeCharacter;

  229.         private String[] headerComments;

  230.         private String[] headers;

  231.         private boolean ignoreEmptyLines;

  232.         private boolean ignoreHeaderCase;

  233.         private boolean ignoreSurroundingSpaces;

  234.         private String nullString;

  235.         private Character quoteCharacter;

  236.         private String quotedNullString;

  237.         private QuoteMode quoteMode;

  238.         private String recordSeparator;

  239.         private boolean skipHeaderRecord;

  240.         private boolean lenientEof;

  241.         private boolean trailingData;

  242.         private boolean trailingDelimiter;

  243.         private boolean trim;

  244.         /** The maximum number of rows to process, excluding the header row. */
  245.         private long maxRows;

  246.         private Builder() {
  247.             // empty
  248.         }

  249.         private Builder(final CSVFormat csvFormat) {
  250.             this.allowMissingColumnNames = csvFormat.allowMissingColumnNames;
  251.             this.autoFlush = csvFormat.autoFlush;
  252.             this.commentMarker = csvFormat.commentMarker;
  253.             this.delimiter = csvFormat.delimiter;
  254.             this.duplicateHeaderMode = csvFormat.duplicateHeaderMode;
  255.             this.escapeCharacter = csvFormat.escapeCharacter;
  256.             this.headerComments = csvFormat.headerComments;
  257.             this.headers = csvFormat.headers;
  258.             this.ignoreEmptyLines = csvFormat.ignoreEmptyLines;
  259.             this.ignoreHeaderCase = csvFormat.ignoreHeaderCase;
  260.             this.ignoreSurroundingSpaces = csvFormat.ignoreSurroundingSpaces;
  261.             this.lenientEof = csvFormat.lenientEof;
  262.             this.maxRows = csvFormat.maxRows;
  263.             this.nullString = csvFormat.nullString;
  264.             this.quoteCharacter = csvFormat.quoteCharacter;
  265.             this.quoteMode = csvFormat.quoteMode;
  266.             this.quotedNullString = csvFormat.quotedNullString;
  267.             this.recordSeparator = csvFormat.recordSeparator;
  268.             this.skipHeaderRecord = csvFormat.skipHeaderRecord;
  269.             this.trailingData = csvFormat.trailingData;
  270.             this.trailingDelimiter = csvFormat.trailingDelimiter;
  271.             this.trim = csvFormat.trim;
  272.         }

  273.         /**
  274.          * Builds a new CSVFormat instance.
  275.          *
  276.          * @return a new CSVFormat instance.
  277.          * @deprecated Use {@link #get()}.
  278.          */
  279.         @Deprecated
  280.         public CSVFormat build() {
  281.             return get();
  282.         }

  283.         /**
  284.          * Builds a new CSVFormat instance.
  285.          *
  286.          * @return a new CSVFormat instance.
  287.          * @since 1.13.0
  288.          */
  289.         @Override
  290.         public CSVFormat get() {
  291.             return new CSVFormat(this);
  292.         }

  293.         /**
  294.          * Sets the duplicate header names behavior, true to allow, false to disallow.
  295.          *
  296.          * @param allowDuplicateHeaderNames the duplicate header names behavior, true to allow, false to disallow.
  297.          * @return This instance.
  298.          * @deprecated Use {@link #setDuplicateHeaderMode(DuplicateHeaderMode)}.
  299.          */
  300.         @Deprecated
  301.         public Builder setAllowDuplicateHeaderNames(final boolean allowDuplicateHeaderNames) {
  302.             setDuplicateHeaderMode(allowDuplicateHeaderNames ? DuplicateHeaderMode.ALLOW_ALL : DuplicateHeaderMode.ALLOW_EMPTY);
  303.             return this;
  304.         }

  305.         /**
  306.          * Sets the parser missing column names behavior, {@code true} to allow missing column names in the header line, {@code false} to cause an
  307.          * {@link IllegalArgumentException} to be thrown.
  308.          *
  309.          * @param allowMissingColumnNames the missing column names behavior, {@code true} to allow missing column names in the header line, {@code false} to
  310.          *                                cause an {@link IllegalArgumentException} to be thrown.
  311.          * @return This instance.
  312.          */
  313.         public Builder setAllowMissingColumnNames(final boolean allowMissingColumnNames) {
  314.             this.allowMissingColumnNames = allowMissingColumnNames;
  315.             return this;
  316.         }

  317.         /**
  318.          * Sets whether to flush on close.
  319.          *
  320.          * @param autoFlush whether to flush on close.
  321.          * @return This instance.
  322.          */
  323.         public Builder setAutoFlush(final boolean autoFlush) {
  324.             this.autoFlush = autoFlush;
  325.             return this;
  326.         }

  327.         /**
  328.          * Sets the comment marker character, use {@code null} to disable comments.
  329.          * <p>
  330.          * The comment start character is only recognized at the start of a line.
  331.          * </p>
  332.          * <p>
  333.          * Comments are printed first, before headers.
  334.          * </p>
  335.          * <p>
  336.          * Use {@link #setCommentMarker(char)} or {@link #setCommentMarker(Character)} to set the comment marker written at the start of each comment line.
  337.          * </p>
  338.          * <p>
  339.          * If the comment marker is not set, then the header comments are ignored.
  340.          * </p>
  341.          * <p>
  342.          * For example:
  343.          * </p>
  344.          *
  345.          * <pre>
  346.          * builder.setCommentMarker('#').setHeaderComments("Generated by Apache Commons CSV", Instant.ofEpochMilli(0));
  347.          * </pre>
  348.          * <p>
  349.          * writes:
  350.          * </p>
  351.          *
  352.          * <pre>
  353.          * # Generated by Apache Commons CSV.
  354.          * # 1970-01-01T00:00:00Z
  355.          * </pre>
  356.          *
  357.          * @param commentMarker the comment start marker, use {@code null} to disable.
  358.          * @return This instance.
  359.          * @throws IllegalArgumentException thrown if the specified character is a line break
  360.          */
  361.         public Builder setCommentMarker(final char commentMarker) {
  362.             setCommentMarker(Character.valueOf(commentMarker));
  363.             return this;
  364.         }

  365.         /**
  366.          * Sets the comment marker character, use {@code null} to disable comments.
  367.          * <p>
  368.          * The comment start character is only recognized at the start of a line.
  369.          * </p>
  370.          * <p>
  371.          * Comments are printed first, before headers.
  372.          * </p>
  373.          * <p>
  374.          * Use {@link #setCommentMarker(char)} or {@link #setCommentMarker(Character)} to set the comment marker written at the start of each comment line.
  375.          * </p>
  376.          * <p>
  377.          * If the comment marker is not set, then the header comments are ignored.
  378.          * </p>
  379.          * <p>
  380.          * For example:
  381.          * </p>
  382.          *
  383.          * <pre>
  384.          * builder.setCommentMarker('#').setHeaderComments("Generated by Apache Commons CSV", Instant.ofEpochMilli(0));
  385.          * </pre>
  386.          * <p>
  387.          * writes:
  388.          * </p>
  389.          *
  390.          * <pre>
  391.          * # Generated by Apache Commons CSV.
  392.          * # 1970-01-01T00:00:00Z
  393.          * </pre>
  394.          *
  395.          * @param commentMarker the comment start marker, use {@code null} to disable.
  396.          * @return This instance.
  397.          * @throws IllegalArgumentException thrown if the specified character is a line break
  398.          */
  399.         public Builder setCommentMarker(final Character commentMarker) {
  400.             if (isLineBreak(commentMarker)) {
  401.                 throw new IllegalArgumentException("The comment start marker character cannot be a line break");
  402.             }
  403.             this.commentMarker = commentMarker;
  404.             return this;
  405.         }

  406.         /**
  407.          * Sets the delimiter character.
  408.          *
  409.          * @param delimiter the delimiter character.
  410.          * @return This instance.
  411.          */
  412.         public Builder setDelimiter(final char delimiter) {
  413.             return setDelimiter(String.valueOf(delimiter));
  414.         }

  415.         /**
  416.          * Sets the delimiter character.
  417.          *
  418.          * @param delimiter the delimiter character.
  419.          * @return This instance.
  420.          */
  421.         public Builder setDelimiter(final String delimiter) {
  422.             if (containsLineBreak(delimiter)) {
  423.                 throw new IllegalArgumentException("The delimiter cannot be a line break");
  424.             }
  425.             if (delimiter.isEmpty()) {
  426.                 throw new IllegalArgumentException("The delimiter cannot be empty");
  427.             }
  428.             this.delimiter = delimiter;
  429.             return this;
  430.         }

  431.         /**
  432.          * Sets the duplicate header names behavior.
  433.          *
  434.          * @param duplicateHeaderMode the duplicate header names behavior
  435.          * @return This instance.
  436.          * @since 1.10.0
  437.          */
  438.         public Builder setDuplicateHeaderMode(final DuplicateHeaderMode duplicateHeaderMode) {
  439.             this.duplicateHeaderMode = Objects.requireNonNull(duplicateHeaderMode, "duplicateHeaderMode");
  440.             return this;
  441.         }

  442.         /**
  443.          * Sets the escape character.
  444.          *
  445.          * @param escapeCharacter the escape character.
  446.          * @return This instance.
  447.          * @throws IllegalArgumentException thrown if the specified character is a line break
  448.          */
  449.         public Builder setEscape(final char escapeCharacter) {
  450.             setEscape(Character.valueOf(escapeCharacter));
  451.             return this;
  452.         }

  453.         /**
  454.          * Sets the escape character.
  455.          *
  456.          * @param escapeCharacter the escape character.
  457.          * @return This instance.
  458.          * @throws IllegalArgumentException thrown if the specified character is a line break
  459.          */
  460.         public Builder setEscape(final Character escapeCharacter) {
  461.             if (isLineBreak(escapeCharacter)) {
  462.                 throw new IllegalArgumentException("The escape character cannot be a line break");
  463.             }
  464.             this.escapeCharacter = escapeCharacter;
  465.             return this;
  466.         }

  467.         /**
  468.          * Sets the header defined by the given {@link Enum} class.
  469.          *
  470.          * <p>
  471.          * Example:
  472.          * </p>
  473.          *
  474.          * <pre>
  475.          * public enum HeaderEnum {
  476.          *     Name, Email, Phone
  477.          * }
  478.          *
  479.          * Builder builder = builder.setHeader(HeaderEnum.class);
  480.          * </pre>
  481.          * <p>
  482.          * The header is also used by the {@link CSVPrinter}.
  483.          * </p>
  484.          *
  485.          * @param headerEnum the enum defining the header, {@code null} if disabled, empty if parsed automatically, user-specified otherwise.
  486.          * @return This instance.
  487.          */
  488.         public Builder setHeader(final Class<? extends Enum<?>> headerEnum) {
  489.             String[] header = null;
  490.             if (headerEnum != null) {
  491.                 final Enum<?>[] enumValues = headerEnum.getEnumConstants();
  492.                 header = new String[enumValues.length];
  493.                 Arrays.setAll(header, i -> enumValues[i].name());
  494.             }
  495.             return setHeader(header);
  496.         }

  497.         /**
  498.          * Sets the header from the result set metadata. The header can be parsed automatically from the input file with:
  499.          *
  500.          * <pre>
  501.          * builder.setHeader();
  502.          * </pre>
  503.          *
  504.          * or specified manually with:
  505.          *
  506.          * <pre>
  507.          * builder.setHeader(resultSet);
  508.          * </pre>
  509.          * <p>
  510.          * The header is also used by the {@link CSVPrinter}.
  511.          * </p>
  512.          *
  513.          * @param resultSet the resultSet for the header, {@code null} if disabled, empty if parsed automatically, user-specified otherwise.
  514.          * @return This instance.
  515.          * @throws SQLException SQLException if a database access error occurs or this method is called on a closed result set.
  516.          */
  517.         public Builder setHeader(final ResultSet resultSet) throws SQLException {
  518.             return setHeader(resultSet != null ? resultSet.getMetaData() : null);
  519.         }

  520.         /**
  521.          * Sets the header from the result set metadata. The header can be parsed automatically from the input file with:
  522.          *
  523.          * <pre>
  524.          * builder.setHeader();
  525.          * </pre>
  526.          *
  527.          * or specified manually with:
  528.          *
  529.          * <pre>
  530.          * builder.setHeader(resultSetMetaData);
  531.          * </pre>
  532.          * <p>
  533.          * The header is also used by the {@link CSVPrinter}.
  534.          * </p>
  535.          *
  536.          * @param resultSetMetaData the metaData for the header, {@code null} if disabled, empty if parsed automatically, user-specified otherwise.
  537.          * @return This instance.
  538.          * @throws SQLException SQLException if a database access error occurs or this method is called on a closed result set.
  539.          */
  540.         public Builder setHeader(final ResultSetMetaData resultSetMetaData) throws SQLException {
  541.             String[] labels = null;
  542.             if (resultSetMetaData != null) {
  543.                 final int columnCount = resultSetMetaData.getColumnCount();
  544.                 labels = new String[columnCount];
  545.                 for (int i = 0; i < columnCount; i++) {
  546.                     labels[i] = resultSetMetaData.getColumnLabel(i + 1);
  547.                 }
  548.             }
  549.             return setHeader(labels);
  550.         }

  551.         /**
  552.          * Sets the header to the given values. The header can be parsed automatically from the input file with:
  553.          *
  554.          * <pre>
  555.          * builder.setHeader();
  556.          * </pre>
  557.          *
  558.          * or specified manually with:
  559.          *
  560.          * <pre>{@code
  561.          * builder.setHeader("name", "email", "phone");
  562.          * }</pre>
  563.          * <p>
  564.          * The header is also used by the {@link CSVPrinter}.
  565.          * </p>
  566.          * <p>
  567.          * This method keeps a copy of the input array.
  568.          * </p>
  569.          * @param header the header, {@code null} if disabled, empty if parsed automatically, user-specified otherwise.
  570.          * @return This instance.
  571.          */
  572.         public Builder setHeader(final String... header) {
  573.             this.headers = CSVFormat.clone(header);
  574.             return this;
  575.         }

  576.         /**
  577.          * Sets the header comments to write before the CSV data.
  578.          * <p>
  579.          * This setting is ignored by the parser.
  580.          * </p>
  581.          * <p>
  582.          * Comments are printed first, before headers.
  583.          * </p>
  584.          * <p>
  585.          * Use {@link #setCommentMarker(char)} or {@link #setCommentMarker(Character)} to set the comment marker written at the start of each comment line.
  586.          * </p>
  587.          * <p>
  588.          * If the comment marker is not set, then the header comments are ignored.
  589.          * </p>
  590.          * <p>
  591.          * For example:
  592.          * </p>
  593.          *
  594.          * <pre>
  595.          * builder.setCommentMarker('#').setHeaderComments("Generated by Apache Commons CSV", Instant.ofEpochMilli(0));
  596.          * </pre>
  597.          * <p>
  598.          * writes:
  599.          * </p>
  600.          *
  601.          * <pre>
  602.          * # Generated by Apache Commons CSV.
  603.          * # 1970-01-01T00:00:00Z
  604.          * </pre>
  605.          * <p>
  606.          * This method keeps a copy of the input array.
  607.          * </p>
  608.          *
  609.          * @param headerComments the headerComments which will be printed by the Printer before the CSV data.
  610.          * @return This instance.
  611.          */
  612.         public Builder setHeaderComments(final Object... headerComments) {
  613.             this.headerComments = CSVFormat.clone(toStringArray(headerComments));
  614.             return this;
  615.         }

  616.         /**
  617.          * Sets the header comments to write before the CSV data.
  618.          * <p>
  619.          * This setting is ignored by the parser.
  620.          * </p>
  621.          * <p>
  622.          * Comments are printed first, before headers.
  623.          * </p>
  624.          * <p>
  625.          * Use {@link #setCommentMarker(char)} or {@link #setCommentMarker(Character)} to set the comment marker written at the start of each comment line.
  626.          * </p>
  627.          * <p>
  628.          * If the comment marker is not set, then the header comments are ignored.
  629.          * </p>
  630.          * <p>
  631.          * For example:
  632.          * </p>
  633.          *
  634.          * <pre>
  635.          * builder.setCommentMarker('#').setHeaderComments("Generated by Apache Commons CSV", Instant.ofEpochMilli(0).toString());
  636.          * </pre>
  637.          * <p>
  638.          * writes:
  639.          * </p>
  640.          *
  641.          * <pre>
  642.          * # Generated by Apache Commons CSV.
  643.          * # 1970-01-01T00:00:00Z
  644.          * </pre>
  645.          * <p>
  646.          * This method keeps a copy of the input array.
  647.          * </p>
  648.          * @param headerComments the headerComments which will be printed by the Printer before the CSV data.
  649.          * @return This instance.
  650.          */
  651.         public Builder setHeaderComments(final String... headerComments) {
  652.             this.headerComments = CSVFormat.clone(headerComments);
  653.             return this;
  654.         }

  655.         /**
  656.          * Sets the empty line skipping behavior, {@code true} to ignore the empty lines between the records, {@code false} to translate empty lines to empty
  657.          * records.
  658.          *
  659.          * @param ignoreEmptyLines the empty line skipping behavior, {@code true} to ignore the empty lines between the records, {@code false} to translate
  660.          *                         empty lines to empty records.
  661.          * @return This instance.
  662.          */
  663.         public Builder setIgnoreEmptyLines(final boolean ignoreEmptyLines) {
  664.             this.ignoreEmptyLines = ignoreEmptyLines;
  665.             return this;
  666.         }

  667.         /**
  668.          * Sets the parser case mapping behavior, {@code true} to access name/values, {@code false} to leave the mapping as is.
  669.          *
  670.          * @param ignoreHeaderCase the case mapping behavior, {@code true} to access name/values, {@code false} to leave the mapping as is.
  671.          * @return This instance.
  672.          */
  673.         public Builder setIgnoreHeaderCase(final boolean ignoreHeaderCase) {
  674.             this.ignoreHeaderCase = ignoreHeaderCase;
  675.             return this;
  676.         }

  677.         /**
  678.          * Sets the parser trimming behavior, {@code true} to remove the surrounding spaces, {@code false} to leave the spaces as is.
  679.          *
  680.          * @param ignoreSurroundingSpaces the parser trimming behavior, {@code true} to remove the surrounding spaces, {@code false} to leave the spaces as is.
  681.          * @return This instance.
  682.          */
  683.         public Builder setIgnoreSurroundingSpaces(final boolean ignoreSurroundingSpaces) {
  684.             this.ignoreSurroundingSpaces = ignoreSurroundingSpaces;
  685.             return this;
  686.         }

  687.         /**
  688.          * Sets whether reading end-of-file is allowed even when input is malformed, helps Excel compatibility.
  689.          *
  690.          * @param lenientEof whether reading end-of-file is allowed even when input is malformed, helps Excel compatibility.
  691.          * @return This instance.
  692.          * @since 1.11.0
  693.          */
  694.         public Builder setLenientEof(final boolean lenientEof) {
  695.             this.lenientEof = lenientEof;
  696.             return this;
  697.         }

  698.         /**
  699.          * Sets the maximum number of rows to process, excluding the header row.
  700.          * <p>
  701.          * Values less than or equal to 0 mean no limit.
  702.          * </p>
  703.          *
  704.          * @param maxRows the maximum number of rows to process, excluding the header row.
  705.          * @return This instance.
  706.          * @since 1.14.0
  707.          */
  708.         public Builder setMaxRows(final long maxRows) {
  709.             this.maxRows = maxRows;
  710.             return this;
  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.          * Sets the quote character.
  730.          *
  731.          * @param quoteCharacter the quote character.
  732.          * @return This instance.
  733.          */
  734.         public Builder setQuote(final char quoteCharacter) {
  735.             setQuote(Character.valueOf(quoteCharacter));
  736.             return this;
  737.         }

  738.         /**
  739.          * Sets the quote character, use {@code null} to disable.
  740.          *
  741.          * @param quoteCharacter the quote character, use {@code null} to disable.
  742.          * @return This instance.
  743.          */
  744.         public Builder setQuote(final Character quoteCharacter) {
  745.             if (isLineBreak(quoteCharacter)) {
  746.                 throw new IllegalArgumentException("The quoteCharacter cannot be a line break");
  747.             }
  748.             this.quoteCharacter = quoteCharacter;
  749.             return this;
  750.         }

  751.         /**
  752.          * Sets the quote policy to use for output.
  753.          *
  754.          * @param quoteMode the quote policy to use for output.
  755.          * @return This instance.
  756.          */
  757.         public Builder setQuoteMode(final QuoteMode quoteMode) {
  758.             this.quoteMode = quoteMode;
  759.             return this;
  760.         }

  761.         /**
  762.          * Sets the record separator to use for output.
  763.          *
  764.          * <p>
  765.          * <strong>Note:</strong> This setting is only used during printing and does not affect parsing. Parsing currently only works for inputs with '\n', '\r'
  766.          * and "\r\n"
  767.          * </p>
  768.          *
  769.          * @param recordSeparator the record separator to use for output.
  770.          * @return This instance.
  771.          */
  772.         public Builder setRecordSeparator(final char recordSeparator) {
  773.             this.recordSeparator = String.valueOf(recordSeparator);
  774.             return this;
  775.         }

  776.         /**
  777.          * Sets the record separator to use for output.
  778.          *
  779.          * <p>
  780.          * <strong>Note:</strong> This setting is only used during printing and does not affect parsing. Parsing currently only works for inputs with '\n', '\r'
  781.          * and "\r\n"
  782.          * </p>
  783.          *
  784.          * @param recordSeparator the record separator to use for output.
  785.          * @return This instance.
  786.          */
  787.         public Builder setRecordSeparator(final String recordSeparator) {
  788.             this.recordSeparator = recordSeparator;
  789.             return this;
  790.         }

  791.         /**
  792.          * Sets whether to skip the header record.
  793.          *
  794.          * @param skipHeaderRecord whether to skip the header record.
  795.          * @return This instance.
  796.          */
  797.         public Builder setSkipHeaderRecord(final boolean skipHeaderRecord) {
  798.             this.skipHeaderRecord = skipHeaderRecord;
  799.             return this;
  800.         }

  801.         /**
  802.          * Sets whether reading trailing data is allowed in records, helps Excel compatibility.
  803.          *
  804.          * @param trailingData whether reading trailing data is allowed in records, helps Excel compatibility.
  805.          * @return This instance.
  806.          * @since 1.11.0
  807.          */
  808.         public Builder setTrailingData(final boolean trailingData) {
  809.             this.trailingData = trailingData;
  810.             return this;
  811.         }

  812.         /**
  813.          * Sets whether to add a trailing delimiter.
  814.          *
  815.          * @param trailingDelimiter whether to add a trailing delimiter.
  816.          * @return This instance.
  817.          */
  818.         public Builder setTrailingDelimiter(final boolean trailingDelimiter) {
  819.             this.trailingDelimiter = trailingDelimiter;
  820.             return this;
  821.         }


  822.         /**
  823.          * Sets whether to trim leading and trailing blanks.
  824.          *
  825.          * @param trim whether to trim leading and trailing blanks.
  826.          * @return This instance.
  827.          */
  828.         public Builder setTrim(final boolean trim) {
  829.             this.trim = trim;
  830.             return this;
  831.         }
  832.     }

  833.     /**
  834.      * Predefines formats.
  835.      *
  836.      * @since 1.2
  837.      */
  838.     public enum Predefined {

  839.         /**
  840.          * The DEFAULT predefined format.
  841.          *
  842.          * @see CSVFormat#DEFAULT
  843.          */
  844.         Default(DEFAULT),

  845.         /**
  846.          * The EXCEL predefined format.
  847.          *
  848.          * @see CSVFormat#EXCEL
  849.          */
  850.         Excel(EXCEL),

  851.         /**
  852.          * The INFORMIX_UNLOAD predefined format.
  853.          *
  854.          * @see CSVFormat#INFORMIX_UNLOAD
  855.          * @since 1.3
  856.          */
  857.         InformixUnload(INFORMIX_UNLOAD),

  858.         /**
  859.          * The INFORMIX_UNLOAD_CSV predefined format.
  860.          *
  861.          * @see CSVFormat#INFORMIX_UNLOAD_CSV
  862.          * @since 1.3
  863.          */
  864.         InformixUnloadCsv(INFORMIX_UNLOAD_CSV),

  865.         /**
  866.          * The MONGODB_CSV predefined format.
  867.          *
  868.          * @see CSVFormat#MONGODB_CSV
  869.          * @since 1.7
  870.          */
  871.         MongoDBCsv(MONGODB_CSV),

  872.         /**
  873.          * The MONGODB_TSV predefined format.
  874.          *
  875.          * @see CSVFormat#MONGODB_TSV
  876.          * @since 1.7
  877.          */
  878.         MongoDBTsv(MONGODB_TSV),

  879.         /**
  880.          * The MYSQL predefined format.
  881.          *
  882.          * @see CSVFormat#MYSQL
  883.          */
  884.         MySQL(MYSQL),

  885.         /**
  886.          * The ORACLE predefined format.
  887.          *
  888.          * @see CSVFormat#ORACLE
  889.          */
  890.         Oracle(ORACLE),

  891.         /**
  892.          * The POSTGRESQL_CSV predefined format.
  893.          *
  894.          * @see CSVFormat#POSTGRESQL_CSV
  895.          * @since 1.5
  896.          */
  897.         PostgreSQLCsv(POSTGRESQL_CSV),

  898.         /**
  899.          * The POSTGRESQL_TEXT predefined format.
  900.          *
  901.          * @see CSVFormat#POSTGRESQL_TEXT
  902.          */
  903.         PostgreSQLText(POSTGRESQL_TEXT),

  904.         /**
  905.          * The RFC4180 predefined format.
  906.          *
  907.          * @see CSVFormat#RFC4180
  908.          */
  909.         RFC4180(CSVFormat.RFC4180),

  910.         /**
  911.          * The TDF predefined format.
  912.          *
  913.          * @see CSVFormat#TDF
  914.          */
  915.         TDF(CSVFormat.TDF);

  916.         private final CSVFormat format;

  917.         Predefined(final CSVFormat format) {
  918.             this.format = format;
  919.         }

  920.         /**
  921.          * Gets the format.
  922.          *
  923.          * @return the format.
  924.          */
  925.         public CSVFormat getFormat() {
  926.             return format;
  927.         }
  928.     }

  929.     /**
  930.      * Standard Comma Separated Value format, as for {@link #RFC4180} but allowing empty lines.
  931.      *
  932.      * <p>
  933.      * The {@link Builder} settings are:
  934.      * </p>
  935.      * <ul>
  936.      * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')}</li>
  937.      * <li>{@link Builder#setQuote(char) setQuote}{@code ('"')}</li>
  938.      * <li>{@link Builder#setRecordSeparator(String) setRecordSeparator}{@code ("\r\n")}</li>
  939.      * <li>{@link Builder#setIgnoreEmptyLines(boolean) setIgnoreEmptyLines}{@code (true)}</li>
  940.      * <li>{@link Builder#setDuplicateHeaderMode(DuplicateHeaderMode) setDuplicateHeaderMode}{@code (DuplicateHeaderMode.ALLOW_ALL)}</li>
  941.      * </ul>
  942.      *
  943.      * @see Predefined#Default
  944.      * @see DuplicateHeaderMode#ALLOW_ALL
  945.      */
  946.     public static final CSVFormat DEFAULT = new CSVFormat(Builder.create());

  947.     /**
  948.      * <a href="https://support.microsoft.com/en-us/office/import-or-export-text-txt-or-csv-files-5250ac4c-663c-47ce-937b-339e391393ba">Microsoft Excel</a> file
  949.      * format (using a comma as the value delimiter). Note that the actual value delimiter used by Excel is locale-dependent, it might be necessary to customize
  950.      * this format to accommodate your regional settings.
  951.      *
  952.      * <p>
  953.      * For example for parsing or generating a CSV file on a French system the following format will be used:
  954.      * </p>
  955.      *
  956.      * <pre>
  957.      * CSVFormat format = CSVFormat.EXCEL.builder().setDelimiter(';').get();
  958.      * </pre>
  959.      *
  960.      * <p>
  961.      * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
  962.      * </p>
  963.      * <ul>
  964.      * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')}</li>
  965.      * <li>{@link Builder#setQuote(char) setQuote}{@code ('"')}</li>
  966.      * <li>{@link Builder#setRecordSeparator(String) setRecordSeparator}{@code ("\r\n")}</li>
  967.      * <li>{@link Builder#setDuplicateHeaderMode(DuplicateHeaderMode) setDuplicateHeaderMode}{@code (DuplicateHeaderMode.ALLOW_ALL)}</li>
  968.      * <li>{@link Builder#setIgnoreEmptyLines(boolean) setIgnoreEmptyLines}{@code (false)}</li>
  969.      * <li>{@link Builder#setAllowMissingColumnNames(boolean) setAllowMissingColumnNames}{@code (true)}</li>
  970.      * <li>{@link Builder#setTrailingData(boolean) setTrailingData}{@code (true)}</li>
  971.      * <li>{@link Builder#setLenientEof(boolean) setLenientEof}{@code (true)}</li>
  972.      * </ul>
  973.      * <p>
  974.      * Note: This is currently like {@link #RFC4180} plus {@link Builder#setAllowMissingColumnNames(boolean) Builder#setAllowMissingColumnNames(true)} and
  975.      * {@link Builder#setIgnoreEmptyLines(boolean) Builder#setIgnoreEmptyLines(false)}.
  976.      * </p>
  977.      *
  978.      * @see Predefined#Excel
  979.      * @see DuplicateHeaderMode#ALLOW_ALL
  980.      * @see <a href="https://support.microsoft.com/en-us/office/import-or-export-text-txt-or-csv-files-5250ac4c-663c-47ce-937b-339e391393ba">Microsoft Excel
  981.      *      </a>
  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.             .get();
  990.     // @formatter:on

  991.     /**
  992.      * Default <a href="https://www.ibm.com/docs/en/informix-servers/14.10?topic=statements-unload-statement">Informix CSV UNLOAD</a>
  993.      * 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 the {@link #DEFAULT} <em>with</em>:
  1002.      * </p>
  1003.      * <ul>
  1004.      * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')}</li>
  1005.      * <li>{@link Builder#setEscape(char) setEscape}{@code ('\\')}</li>
  1006.      * <li>{@link Builder#setQuote(char) setQuote}{@code ('\"')}</li>
  1007.      * <li>{@link Builder#setRecordSeparator(char) setRecordSeparator}{@code ('\n')}</li>
  1008.      * </ul>
  1009.      *
  1010.      * @see Predefined#MySQL
  1011.      * @see <a href="https://www.ibm.com/docs/en/informix-servers/14.10?topic=statements-unload-statement">Informix CSV UNLOAD</a>
  1012.      * @since 1.3
  1013.      */
  1014.     // @formatter:off
  1015.     public static final CSVFormat INFORMIX_UNLOAD = DEFAULT.builder()
  1016.             .setDelimiter(Constants.PIPE)
  1017.             .setEscape(Constants.BACKSLASH)
  1018.             .setQuote(Constants.DOUBLE_QUOTE_CHAR)
  1019.             .setRecordSeparator(Constants.LF)
  1020.             .get();
  1021.     // @formatter:on

  1022.     /**
  1023.      * Default <a href="https://www.ibm.com/docs/en/informix-servers/14.10?topic=statements-unload-statement">Informix CSV UNLOAD</a>
  1024.      * format used by the {@code UNLOAD TO file_name} operation (escaping is disabled.)
  1025.      *
  1026.      * <p>
  1027.      * 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 '\'}.
  1028.      * The default NULL string is {@code "\\N"}.
  1029.      * </p>
  1030.      *
  1031.      * <p>
  1032.      * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
  1033.      * </p>
  1034.      * <ul>
  1035.      * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')}</li>
  1036.      * <li>{@link Builder#setQuote(char) setQuote}{@code ('\"')}</li>
  1037.      * <li>{@link Builder#setRecordSeparator(char) setRecordSeparator}{@code ('\n')}</li>
  1038.      * </ul>
  1039.      *
  1040.      * @see Predefined#MySQL
  1041.      * @see <a href= "http://www.ibm.com/support/knowledgecenter/SSBJG3_2.5.0/com.ibm.gen_busug.doc/c_fgl_InOutSql_UNLOAD.htm">
  1042.      *      http://www.ibm.com/support/knowledgecenter/SSBJG3_2.5.0/com.ibm.gen_busug.doc/c_fgl_InOutSql_UNLOAD.htm</a>
  1043.      * @since 1.3
  1044.      */
  1045.     // @formatter:off
  1046.     public static final CSVFormat INFORMIX_UNLOAD_CSV = DEFAULT.builder()
  1047.             .setDelimiter(Constants.COMMA)
  1048.             .setQuote(Constants.DOUBLE_QUOTE_CHAR)
  1049.             .setRecordSeparator(Constants.LF)
  1050.             .get();
  1051.     // @formatter:on

  1052.     /**
  1053.      * Default MongoDB CSV format used by the {@code mongoexport} operation.
  1054.      * <p>
  1055.      * <strong>Parsing is not supported yet.</strong>
  1056.      * </p>
  1057.      *
  1058.      * <p>
  1059.      * 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
  1060.      * names is expected.
  1061.      * </p>
  1062.      * <p>
  1063.      * As of 2024-04-05, the MongoDB documentation for {@code mongoimport} states:
  1064.      * </p>
  1065.      * <blockquote>The csv parser accepts that data that complies with RFC <a href="https://tools.ietf.org/html/4180">RFC-4180</a>. As a result, backslashes are
  1066.      * not a valid escape character. If you use double-quotes to enclose fields in the CSV data, you must escape internal double-quote marks by prepending
  1067.      * another double-quote. </blockquote>
  1068.      * <p>
  1069.      * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
  1070.      * </p>
  1071.      * <ul>
  1072.      * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')}</li>
  1073.      * <li>{@link Builder#setEscape(char) setEscape}{@code ('"')}</li>
  1074.      * <li>{@link Builder#setQuote(char) setQuote}{@code ('"')}</li>
  1075.      * <li>{@link Builder#setQuoteMode(QuoteMode) setQuoteMode}{@code (QuoteMode.MINIMAL)}</li>
  1076.      * </ul>
  1077.      *
  1078.      * @see Predefined#MongoDBCsv
  1079.      * @see QuoteMode#ALL_NON_NULL
  1080.      * @see <a href="https://docs.mongodb.com/manual/reference/program/mongoexport/">MongoDB mongoexport command documentation</a>
  1081.      * @since 1.7
  1082.      */
  1083.     // @formatter:off
  1084.     public static final CSVFormat MONGODB_CSV = DEFAULT.builder()
  1085.             .setDelimiter(Constants.COMMA)
  1086.             .setEscape(Constants.DOUBLE_QUOTE_CHAR)
  1087.             .setQuote(Constants.DOUBLE_QUOTE_CHAR)
  1088.             .setQuoteMode(QuoteMode.MINIMAL)
  1089.             .get();
  1090.     // @formatter:off

  1091.     /**
  1092.      * Default MongoDB TSV format used by the {@code mongoexport} operation.
  1093.      * <p>
  1094.      * <strong>Parsing is not supported yet.</strong>
  1095.      * </p>
  1096.      *
  1097.      * <p>
  1098.      * This is a tab-delimited format. Values are double quoted only if needed and special
  1099.      * characters are escaped with {@code '"'}. A header line with field names is expected.
  1100.      * </p>
  1101.      *
  1102.      * <p>
  1103.      * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
  1104.      * </p>
  1105.      * <ul>
  1106.      * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code ('\t')}</li>
  1107.      * <li>{@link Builder#setEscape(char) setEscape}{@code ('"')}</li>
  1108.      * <li>{@link Builder#setQuote(char) setQuote}{@code ('"')}</li>
  1109.      * <li>{@link Builder#setQuoteMode(QuoteMode) setQuoteMode}{@code (QuoteMode.MINIMAL)}</li>
  1110.      * <li>{@link Builder#setSkipHeaderRecord(boolean) setSkipHeaderRecord}{@code (false)}</li>
  1111.      * </ul>
  1112.      *
  1113.      * @see Predefined#MongoDBCsv
  1114.      * @see QuoteMode#ALL_NON_NULL
  1115.      * @see <a href="https://docs.mongodb.com/manual/reference/program/mongoexport/">MongoDB mongoexport command
  1116.      *          documentation</a>
  1117.      * @since 1.7
  1118.      */
  1119.     // @formatter:off
  1120.     public static final CSVFormat MONGODB_TSV = DEFAULT.builder()
  1121.             .setDelimiter(Constants.TAB)
  1122.             .setEscape(Constants.DOUBLE_QUOTE_CHAR)
  1123.             .setQuote(Constants.DOUBLE_QUOTE_CHAR)
  1124.             .setQuoteMode(QuoteMode.MINIMAL)
  1125.             .setSkipHeaderRecord(false)
  1126.             .get();
  1127.     // @formatter:off

  1128.     /**
  1129.      * Default <a href="https://dev.mysql.com/doc/refman/8.0/en/mysqldump-delimited-text.html">MySQL</a>
  1130.      * format used by the {@code SELECT INTO OUTFILE} and {@code LOAD DATA INFILE} operations.
  1131.      *
  1132.      * <p>
  1133.      * This is a tab-delimited format with an LF character as the line separator. Values are not quoted and special
  1134.      * characters are escaped with {@code '\'}. The default NULL string is {@code "\\N"}.
  1135.      * </p>
  1136.      *
  1137.      * <p>
  1138.      * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
  1139.      * </p>
  1140.      * <ul>
  1141.      * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code ('\t')}</li>
  1142.      * <li>{@link Builder#setEscape(char) setEscape}{@code ('\\')}</li>
  1143.      * <li>{@link Builder#setIgnoreEmptyLines(boolean) setIgnoreEmptyLines}{@code (false)}</li>
  1144.      * <li>{@link Builder#setQuote(Character) setQuote}{@code (null)}</li>
  1145.      * <li>{@link Builder#setRecordSeparator(char) setRecordSeparator}{@code ('\n')}</li>
  1146.      * <li>{@link Builder#setNullString(String) setNullString}{@code ("\\N")}</li>
  1147.      * <li>{@link Builder#setQuoteMode(QuoteMode) setQuoteMode}{@code (QuoteMode.ALL_NON_NULL)}</li>
  1148.      * </ul>
  1149.      *
  1150.      * @see Predefined#MySQL
  1151.      * @see QuoteMode#ALL_NON_NULL
  1152.      * @see <a href="https://dev.mysql.com/doc/refman/8.0/en/mysqldump-delimited-text.html">MySQL</a>
  1153.      */
  1154.     // @formatter:off
  1155.     public static final CSVFormat MYSQL = DEFAULT.builder()
  1156.             .setDelimiter(Constants.TAB)
  1157.             .setEscape(Constants.BACKSLASH)
  1158.             .setIgnoreEmptyLines(false)
  1159.             .setQuote(null)
  1160.             .setRecordSeparator(Constants.LF)
  1161.             .setNullString(Constants.SQL_NULL_STRING)
  1162.             .setQuoteMode(QuoteMode.ALL_NON_NULL)
  1163.             .get();
  1164.     // @formatter:off

  1165.     /**
  1166.      * Default
  1167.      * <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/sutil/oracle-sql-loader-control-file-contents.html#GUID-D1762699-8154-40F6-90DE-EFB8EB6A9AB0">Oracle</a>
  1168.      * format used by the SQL*Loader utility.
  1169.      *
  1170.      * <p>
  1171.      * This is a comma-delimited format with the system line separator character as the record separator. Values are
  1172.      * double quoted when needed and special characters are escaped with {@code '"'}. The default NULL string is
  1173.      * {@code ""}. Values are trimmed.
  1174.      * </p>
  1175.      *
  1176.      * <p>
  1177.      * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
  1178.      * </p>
  1179.      * <ul>
  1180.      * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')} // default is {@code FIELDS TERMINATED BY ','}}</li>
  1181.      * <li>{@link Builder#setEscape(char) setEscape}{@code ('\\')}</li>
  1182.      * <li>{@link Builder#setIgnoreEmptyLines(boolean) setIgnoreEmptyLines}{@code (false)}</li>
  1183.      * <li>{@link Builder#setQuote(char) setQuote}{@code ('"')} // default is {@code OPTIONALLY ENCLOSED BY '"'}}</li>
  1184.      * <li>{@link Builder#setNullString(String) setNullString}{@code ("\\N")}</li>
  1185.      * <li>{@link Builder#setTrim(boolean) setTrim}{@code (true)}</li>
  1186.      * <li>{@link Builder#setRecordSeparator(String) setRecordSeparator}{@code (System.lineSeparator())}</li>
  1187.      * <li>{@link Builder#setQuoteMode(QuoteMode) setQuoteMode}{@code (QuoteMode.MINIMAL)}</li>
  1188.      * </ul>
  1189.      *
  1190.      * @see Predefined#Oracle
  1191.      * @see QuoteMode#MINIMAL
  1192.      * @see <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/sutil/oracle-sql-loader-control-file-contents.html#GUID-D1762699-8154-40F6-90DE-EFB8EB6A9AB0">Oracle CSV Format Specification</a>
  1193.      * @since 1.6
  1194.      */
  1195.     // @formatter:off
  1196.     public static final CSVFormat ORACLE = DEFAULT.builder()
  1197.             .setDelimiter(Constants.COMMA)
  1198.             .setEscape(Constants.BACKSLASH)
  1199.             .setIgnoreEmptyLines(false)
  1200.             .setQuote(Constants.DOUBLE_QUOTE_CHAR)
  1201.             .setNullString(Constants.SQL_NULL_STRING)
  1202.             .setTrim(true)
  1203.             .setRecordSeparator(System.lineSeparator())
  1204.             .setQuoteMode(QuoteMode.MINIMAL)
  1205.             .get();
  1206.     // @formatter:off

  1207.     /**
  1208.      * Default <a href="https://www.postgresql.org/docs/current/static/sql-copy.html">PostgreSQL CSV</a> format used by the {@code COPY} operation.
  1209.      *
  1210.      * <p>
  1211.      * This is a comma-delimited format with an LF character as the line separator. Values are double quoted and special
  1212.      * characters are not escaped. The default NULL string is {@code ""}.
  1213.      * </p>
  1214.      *
  1215.      * <p>
  1216.      * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
  1217.      * </p>
  1218.      * <ul>
  1219.      * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')}</li>
  1220.      * <li>{@link Builder#setEscape(Character) setEscape}{@code (null)}</li>
  1221.      * <li>{@link Builder#setIgnoreEmptyLines(boolean) setIgnoreEmptyLines}{@code (false)}</li>
  1222.      * <li>{@link Builder#setQuote(char) setQuote}{@code ('"')}</li>
  1223.      * <li>{@link Builder#setRecordSeparator(char) setRecordSeparator}{@code ('\n')}</li>
  1224.      * <li>{@link Builder#setNullString(String) setNullString}{@code ("")}</li>
  1225.      * <li>{@link Builder#setQuoteMode(QuoteMode) setQuoteMode}{@code (QuoteMode.ALL_NON_NULL)}</li>
  1226.      * </ul>
  1227.      *
  1228.      * @see Predefined#MySQL
  1229.      * @see QuoteMode#ALL_NON_NULL
  1230.      * @see <a href="https://www.postgresql.org/docs/current/static/sql-copy.html">PostgreSQL CSV</a>
  1231.      * @since 1.5
  1232.      */
  1233.     // @formatter:off
  1234.     public static final CSVFormat POSTGRESQL_CSV = DEFAULT.builder()
  1235.             .setDelimiter(Constants.COMMA)
  1236.             .setEscape(null)
  1237.             .setIgnoreEmptyLines(false)
  1238.             .setQuote(Constants.DOUBLE_QUOTE_CHAR)
  1239.             .setRecordSeparator(Constants.LF)
  1240.             .setNullString(Constants.EMPTY)
  1241.             .setQuoteMode(QuoteMode.ALL_NON_NULL)
  1242.             .get();
  1243.     // @formatter:off

  1244.     /**
  1245.      * Default <a href="https://www.postgresql.org/docs/current/static/sql-copy.html">PostgreSQL Text</a> format used by the {@code COPY} operation.
  1246.      *
  1247.      * <p>
  1248.      * This is a tab-delimited format with an LF character as the line separator. Values are not quoted and special
  1249.      * characters are escaped with {@code '\\'}. The default NULL string is {@code "\\N"}.
  1250.      * </p>
  1251.      *
  1252.      * <p>
  1253.      * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
  1254.      * </p>
  1255.      * <ul>
  1256.      * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code ('\t')}</li>
  1257.      * <li>{@link Builder#setEscape(char) setEscape}{@code ('\\')}</li>
  1258.      * <li>{@link Builder#setIgnoreEmptyLines(boolean) setIgnoreEmptyLines}{@code (false)}</li>
  1259.      * <li>{@link Builder#setQuote(Character) setQuote}{@code (null)}</li>
  1260.      * <li>{@link Builder#setRecordSeparator(char) setRecordSeparator}{@code ('\n')}</li>
  1261.      * <li>{@link Builder#setNullString(String) setNullString}{@code ("\\N")}</li>
  1262.      * <li>{@link Builder#setQuoteMode(QuoteMode) setQuoteMode}{@code (QuoteMode.ALL_NON_NULL)}</li>
  1263.      * </ul>
  1264.      *
  1265.      * @see Predefined#MySQL
  1266.      * @see QuoteMode#ALL_NON_NULL
  1267.      * @see <a href="https://www.postgresql.org/docs/current/static/sql-copy.html">PostgreSQL Text</a>
  1268.      * @since 1.5
  1269.      */
  1270.     // @formatter:off
  1271.     public static final CSVFormat POSTGRESQL_TEXT = DEFAULT.builder()
  1272.             .setDelimiter(Constants.TAB)
  1273.             .setEscape(Constants.BACKSLASH)
  1274.             .setIgnoreEmptyLines(false)
  1275.             .setQuote(null)
  1276.             .setRecordSeparator(Constants.LF)
  1277.             .setNullString(Constants.SQL_NULL_STRING)
  1278.             .setQuoteMode(QuoteMode.ALL_NON_NULL)
  1279.             .get();
  1280.     // @formatter:off

  1281.     /**
  1282.      * Comma separated format as defined by <a href="https://tools.ietf.org/html/rfc4180">RFC 4180</a>.
  1283.      *
  1284.      * <p>
  1285.      * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
  1286.      * </p>
  1287.      * <ul>
  1288.      * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code (',')}</li>
  1289.      * <li>{@link Builder#setQuote(char) setQuote}{@code ('"')}</li>
  1290.      * <li>{@link Builder#setRecordSeparator(String) setRecordSeparator}{@code ("\r\n")}</li>
  1291.      * <li>{@link Builder#setIgnoreEmptyLines(boolean) setIgnoreEmptyLines}{@code (false)}</li>
  1292.      * </ul>
  1293.      *
  1294.      * @see Predefined#RFC4180
  1295.      * @see <a href="https://tools.ietf.org/html/rfc4180">RFC 4180</a>
  1296.      */
  1297.     public static final CSVFormat RFC4180 = DEFAULT.builder().setIgnoreEmptyLines(false).get();

  1298.     private static final long serialVersionUID = 2L;

  1299.     /**
  1300.      * Tab-delimited format (<a href="https://en.wikipedia.org/wiki/Tab-separated_values">TDF</a>).
  1301.      *
  1302.      * <p>
  1303.      * The {@link Builder} settings are the {@link #DEFAULT} <em>with</em>:
  1304.      * </p>
  1305.      * <ul>
  1306.      * <li>{@link Builder#setDelimiter(char) setDelimiter}{@code ('\t')}</li>
  1307.      * <li>{@link Builder#setIgnoreSurroundingSpaces(boolean) setIgnoreSurroundingSpaces}{@code (true)}</li>
  1308.      * </ul>
  1309.      *
  1310.      * @see Predefined#TDF
  1311.      * @see <a href="https://en.wikipedia.org/wiki/Tab-separated_values">TDF</a>
  1312.      */
  1313.     // @formatter:off
  1314.     public static final CSVFormat TDF = DEFAULT.builder()
  1315.             .setDelimiter(Constants.TAB)
  1316.             .setIgnoreSurroundingSpaces(true)
  1317.             .get();
  1318.     // @formatter:on

  1319.     /**
  1320.      * Null-safe clone of an array.
  1321.      *
  1322.      * @param <T>    The array element type.
  1323.      * @param values the source array
  1324.      * @return the cloned array.
  1325.      */
  1326.     @SafeVarargs
  1327.     static <T> T[] clone(final T... values) {
  1328.         return values == null ? null : values.clone();
  1329.     }

  1330.     /**
  1331.      * Returns true if the given string contains the search char.
  1332.      *
  1333.      * @param source   the string to check.
  1334.      * @param searchCh the character to search.
  1335.      * @return true if {@code c} contains a line break character
  1336.      */
  1337.     private static boolean contains(final String source, final char searchCh) {
  1338.         return Objects.requireNonNull(source, "source").indexOf(searchCh) >= 0;
  1339.     }

  1340.     /**
  1341.      * Returns true if the given string contains a line break character.
  1342.      *
  1343.      * @param source the string to check.
  1344.      * @return true if {@code c} contains a line break character.
  1345.      */
  1346.     private static boolean containsLineBreak(final String source) {
  1347.         return contains(source, Constants.CR) || contains(source, Constants.LF);
  1348.     }

  1349.     /**
  1350.      * Creates a null-safe copy of the given instance.
  1351.      *
  1352.      * @return a copy of the given instance or null if the input is null.
  1353.      */
  1354.     static CSVFormat copy(final CSVFormat format) {
  1355.         return format != null ? format.copy() : null;
  1356.     }

  1357.     static boolean isBlank(final String value) {
  1358.         return value == null || value.trim().isEmpty();
  1359.     }

  1360.     /**
  1361.      * Returns true if the given character is a line break character.
  1362.      *
  1363.      * @param c the character to check.
  1364.      * @return true if {@code c} is a line break character.
  1365.      */
  1366.     private static boolean isLineBreak(final char c) {
  1367.         return c == Constants.LF || c == Constants.CR;
  1368.     }

  1369.     /**
  1370.      * Returns true if the given character is a line break character.
  1371.      *
  1372.      * @param c the character to check, may be null.
  1373.      * @return true if {@code c} is a line break character (and not null).
  1374.      */
  1375.     private static boolean isLineBreak(final Character c) {
  1376.         return c != null && isLineBreak(c.charValue()); // Explicit (un)boxing is intentional
  1377.     }

  1378.     /** Same test as in as {@link String#trim()}. */
  1379.     private static boolean isTrimChar(final char ch) {
  1380.         return ch <= Constants.SP;
  1381.     }

  1382.     /** Same test as in as {@link String#trim()}. */
  1383.     private static boolean isTrimChar(final CharSequence charSequence, final int pos) {
  1384.         return isTrimChar(charSequence.charAt(pos));
  1385.     }

  1386.     /**
  1387.      * Creates a new CSV format with the specified delimiter.
  1388.      *
  1389.      * <p>
  1390.      * Use this method if you want to create a CSVFormat from scratch. All fields but the delimiter will be initialized with null/false.
  1391.      * </p>
  1392.      *
  1393.      * @param delimiter the char used for value separation, must not be a line break character
  1394.      * @return a new CSV format.
  1395.      * @throws IllegalArgumentException if the delimiter is a line break character
  1396.      * @see #DEFAULT
  1397.      * @see #RFC4180
  1398.      * @see #MYSQL
  1399.      * @see #EXCEL
  1400.      * @see #TDF
  1401.      */
  1402.     public static CSVFormat newFormat(final char delimiter) {
  1403.         return new CSVFormat(new Builder().setDelimiter(delimiter));
  1404.     }

  1405.     static String[] toStringArray(final Object[] values) {
  1406.         if (values == null) {
  1407.             return null;
  1408.         }
  1409.         final String[] strings = new String[values.length];
  1410.         Arrays.setAll(strings, i -> Objects.toString(values[i], null));
  1411.         return strings;
  1412.     }

  1413.     static CharSequence trim(final CharSequence charSequence) {
  1414.         if (charSequence instanceof String) {
  1415.             return ((String) charSequence).trim();
  1416.         }
  1417.         final int count = charSequence.length();
  1418.         int len = count;
  1419.         int pos = 0;

  1420.         while (pos < len && isTrimChar(charSequence, pos)) {
  1421.             pos++;
  1422.         }
  1423.         while (pos < len && isTrimChar(charSequence, len - 1)) {
  1424.             len--;
  1425.         }
  1426.         return pos > 0 || len < count ? charSequence.subSequence(pos, len) : charSequence;
  1427.     }

  1428.     /**
  1429.      * Gets one of the predefined formats from {@link CSVFormat.Predefined}.
  1430.      *
  1431.      * @param format name
  1432.      * @return one of the predefined formats
  1433.      * @since 1.2
  1434.      */
  1435.     public static CSVFormat valueOf(final String format) {
  1436.         return CSVFormat.Predefined.valueOf(format).getFormat();
  1437.     }

  1438.     /** How duplicate headers are handled. */
  1439.     private final DuplicateHeaderMode duplicateHeaderMode;

  1440.     /** Whether missing column names are allowed when parsing the header line. */
  1441.     private final boolean allowMissingColumnNames;

  1442.     /** Whether to flush on close. */
  1443.     private final boolean autoFlush;

  1444.     /** Set to null if commenting is disabled. */
  1445.     private final Character commentMarker;

  1446.     /** The character delimiting the values (typically ";", "," or "\t"). */
  1447.     private final String delimiter;

  1448.     /** Set to null if escaping is disabled. */
  1449.     private final Character escapeCharacter;

  1450.     /** Array of header column names. */
  1451.     private final String[] headers;

  1452.     /** Array of header comment lines. */
  1453.     private final String[] headerComments;

  1454.     /** Whether empty lines between records are ignored when parsing input. */
  1455.     private final boolean ignoreEmptyLines;

  1456.     /** Should ignore header names case. */
  1457.     private final boolean ignoreHeaderCase;

  1458.     /** Should leading/trailing spaces be ignored around values?. */
  1459.     private final boolean ignoreSurroundingSpaces;

  1460.     /** The string to be used for null values. */
  1461.     private final String nullString;

  1462.     /** Set to null if quoting is disabled. */
  1463.     private final Character quoteCharacter;

  1464.     /** Set to {@code quoteCharacter + nullString + quoteCharacter} */
  1465.     private final String quotedNullString;

  1466.     /** The quote policy output fields. */
  1467.     private final QuoteMode quoteMode;

  1468.     /** For output. */
  1469.     private final String recordSeparator;

  1470.     /** Whether to skip the header record. */
  1471.     private final boolean skipHeaderRecord;

  1472.     /** Whether reading end-of-file is allowed even when input is malformed, helps Excel compatibility. */
  1473.     private final boolean lenientEof;

  1474.     /** Whether reading trailing data is allowed in records, helps Excel compatibility. */
  1475.     private final boolean trailingData;

  1476.     /** Whether to add a trailing delimiter. */
  1477.     private final boolean trailingDelimiter;

  1478.     /** Whether to trim leading and trailing blanks. */
  1479.     private final boolean trim;

  1480.     /** The maximum number of rows to process, excluding the header row. */
  1481.     private final long maxRows;

  1482.     private CSVFormat(final Builder builder) {
  1483.         this.allowMissingColumnNames = builder.allowMissingColumnNames;
  1484.         this.autoFlush = builder.autoFlush;
  1485.         this.commentMarker = builder.commentMarker;
  1486.         this.delimiter = builder.delimiter;
  1487.         this.duplicateHeaderMode = builder.duplicateHeaderMode;
  1488.         this.escapeCharacter = builder.escapeCharacter;
  1489.         this.headerComments = builder.headerComments;
  1490.         this.headers = builder.headers;
  1491.         this.ignoreEmptyLines = builder.ignoreEmptyLines;
  1492.         this.ignoreHeaderCase = builder.ignoreHeaderCase;
  1493.         this.ignoreSurroundingSpaces = builder.ignoreSurroundingSpaces;
  1494.         this.lenientEof = builder.lenientEof;
  1495.         this.maxRows = builder.maxRows;
  1496.         this.nullString = builder.nullString;
  1497.         this.quoteCharacter = builder.quoteCharacter;
  1498.         this.quoteMode = builder.quoteMode;
  1499.         this.quotedNullString = builder.quotedNullString;
  1500.         this.recordSeparator = builder.recordSeparator;
  1501.         this.skipHeaderRecord = builder.skipHeaderRecord;
  1502.         this.trailingData = builder.trailingData;
  1503.         this.trailingDelimiter = builder.trailingDelimiter;
  1504.         this.trim = builder.trim;
  1505.         validate();
  1506.     }

  1507.     private void append(final char c, final Appendable appendable) throws IOException {
  1508.         // try {
  1509.         appendable.append(c);
  1510.         // } catch (final IOException e) {
  1511.         // throw new UncheckedIOException(e);
  1512.         // }
  1513.     }

  1514.     private void append(final CharSequence csq, final Appendable appendable) throws IOException {
  1515.         // try {
  1516.         appendable.append(csq);
  1517.         // } catch (final IOException e) {
  1518.         // throw new UncheckedIOException(e);
  1519.         // }
  1520.     }

  1521.     /**
  1522.      * Creates a new Builder for this instance.
  1523.      *
  1524.      * @return a new Builder.
  1525.      */
  1526.     public Builder builder() {
  1527.         return Builder.create(this);
  1528.     }

  1529.     /**
  1530.      * Creates a copy of this instance.
  1531.      *
  1532.      * @return a copy of this instance.
  1533.      */
  1534.     CSVFormat copy() {
  1535.         return builder().get();
  1536.     }

  1537.     @Override
  1538.     public boolean equals(final Object obj) {
  1539.         if (this == obj) {
  1540.             return true;
  1541.         }
  1542.         if (obj == null) {
  1543.             return false;
  1544.         }
  1545.         if (getClass() != obj.getClass()) {
  1546.             return false;
  1547.         }
  1548.         final CSVFormat other = (CSVFormat) obj;
  1549.         return allowMissingColumnNames == other.allowMissingColumnNames && autoFlush == other.autoFlush &&
  1550.                 Objects.equals(commentMarker, other.commentMarker) && Objects.equals(delimiter, other.delimiter) &&
  1551.                 duplicateHeaderMode == other.duplicateHeaderMode && Objects.equals(escapeCharacter, other.escapeCharacter) &&
  1552.                 Arrays.equals(headerComments, other.headerComments) && Arrays.equals(headers, other.headers) &&
  1553.                 ignoreEmptyLines == other.ignoreEmptyLines && ignoreHeaderCase == other.ignoreHeaderCase &&
  1554.                 ignoreSurroundingSpaces == other.ignoreSurroundingSpaces && lenientEof == other.lenientEof &&
  1555.                 Objects.equals(nullString, other.nullString) && Objects.equals(quoteCharacter, other.quoteCharacter) &&
  1556.                 quoteMode == other.quoteMode && Objects.equals(quotedNullString, other.quotedNullString) &&
  1557.                 Objects.equals(recordSeparator, other.recordSeparator) && skipHeaderRecord == other.skipHeaderRecord &&
  1558.                 trailingData == other.trailingData && trailingDelimiter == other.trailingDelimiter && trim == other.trim;
  1559.     }

  1560.     private void escape(final char c, final Appendable appendable) throws IOException {
  1561.         append(escapeCharacter.charValue(), appendable); // Explicit (un)boxing is intentional
  1562.         append(c, appendable);
  1563.     }

  1564.     /**
  1565.      * Formats the specified values as a CSV record string.
  1566.      *
  1567.      * @param values the values to format.
  1568.      * @return the formatted values.
  1569.      */
  1570.     public String format(final Object... values) {
  1571.         return Uncheck.get(() -> format_(values));
  1572.     }

  1573.     private String format_(final Object... values) throws IOException {
  1574.         final StringWriter out = new StringWriter();
  1575.         try (CSVPrinter csvPrinter = new CSVPrinter(out, this)) {
  1576.             csvPrinter.printRecord(values);
  1577.             final String res = out.toString();
  1578.             final int len = recordSeparator != null ? res.length() - recordSeparator.length() : res.length();
  1579.             return res.substring(0, len);
  1580.         }
  1581.     }

  1582.     /**
  1583.      * Gets whether duplicate names are allowed in the headers.
  1584.      *
  1585.      * @return whether duplicate header names are allowed
  1586.      * @since 1.7
  1587.      * @deprecated Use {@link #getDuplicateHeaderMode()}.
  1588.      */
  1589.     @Deprecated
  1590.     public boolean getAllowDuplicateHeaderNames() {
  1591.         return duplicateHeaderMode == DuplicateHeaderMode.ALLOW_ALL;
  1592.     }

  1593.     /**
  1594.      * Gets whether missing column names are allowed when parsing the header line.
  1595.      *
  1596.      * @return {@code true} if missing column names are allowed when parsing the header line, {@code false} to throw an {@link IllegalArgumentException}.
  1597.      */
  1598.     public boolean getAllowMissingColumnNames() {
  1599.         return allowMissingColumnNames;
  1600.     }

  1601.     /**
  1602.      * Gets whether to flush on close.
  1603.      *
  1604.      * @return whether to flush on close.
  1605.      * @since 1.6
  1606.      */
  1607.     public boolean getAutoFlush() {
  1608.         return autoFlush;
  1609.     }

  1610.     /**
  1611.      * Gets the comment marker character, {@code null} disables comments.
  1612.      * <p>
  1613.      * The comment start character is only recognized at the start of a line.
  1614.      * </p>
  1615.      * <p>
  1616.      * Comments are printed first, before headers.
  1617.      * </p>
  1618.      * <p>
  1619.      * Use {@link Builder#setCommentMarker(char)} or {@link Builder#setCommentMarker(Character)} to set the comment marker written at the start of each comment
  1620.      * line.
  1621.      * </p>
  1622.      * <p>
  1623.      * If the comment marker is not set, then the header comments are ignored.
  1624.      * </p>
  1625.      * <p>
  1626.      * For example:
  1627.      * </p>
  1628.      *
  1629.      * <pre>
  1630.      * builder.setCommentMarker('#').setHeaderComments("Generated by Apache Commons CSV", Instant.ofEpochMilli(0));
  1631.      * </pre>
  1632.      * <p>
  1633.      * writes:
  1634.      * </p>
  1635.      *
  1636.      * <pre>
  1637.      * # Generated by Apache Commons CSV.
  1638.      * # 1970-01-01T00:00:00Z
  1639.      * </pre>
  1640.      *
  1641.      * @return the comment start marker, may be {@code null}
  1642.      */
  1643.     public Character getCommentMarker() {
  1644.         return commentMarker;
  1645.     }

  1646.     /**
  1647.      * Gets the first character delimiting the values (typically ';', ',' or '\t').
  1648.      *
  1649.      * @return the first delimiter character.
  1650.      * @deprecated Use {@link #getDelimiterString()}.
  1651.      */
  1652.     @Deprecated
  1653.     public char getDelimiter() {
  1654.         return delimiter.charAt(0);
  1655.     }

  1656.     /**
  1657.      * Gets the character delimiting the values (typically ";", "," or "\t").
  1658.      *
  1659.      * @return the delimiter.
  1660.      */
  1661.     char[] getDelimiterCharArray() {
  1662.         return delimiter.toCharArray();
  1663.     }

  1664.     /**
  1665.      * Gets the character delimiting the values (typically ";", "," or "\t").
  1666.      *
  1667.      * @return the delimiter.
  1668.      * @since 1.9.0
  1669.      */
  1670.     public String getDelimiterString() {
  1671.         return delimiter;
  1672.     }

  1673.     /**
  1674.      * Gets how duplicate headers are handled.
  1675.      *
  1676.      * @return if duplicate header values are allowed, allowed conditionally, or disallowed.
  1677.      * @since 1.10.0
  1678.      */
  1679.     public DuplicateHeaderMode getDuplicateHeaderMode() {
  1680.         return duplicateHeaderMode;
  1681.     }

  1682.     /**
  1683.      * Gets the escape character.
  1684.      *
  1685.      * @return the escape character, may be {@code 0}
  1686.      */
  1687.     char getEscapeChar() {
  1688.         return escapeCharacter != null ? escapeCharacter.charValue() : 0; // Explicit (un)boxing is intentional
  1689.     }

  1690.     /**
  1691.      * Gets the escape character.
  1692.      *
  1693.      * @return the escape character, may be {@code null}
  1694.      */
  1695.     public Character getEscapeCharacter() {
  1696.         return escapeCharacter;
  1697.     }

  1698.     /**
  1699.      * Gets a copy of the header array.
  1700.      *
  1701.      * @return a copy of the header array; {@code null} if disabled, the empty array if to be read from the file
  1702.      */
  1703.     public String[] getHeader() {
  1704.         return headers != null ? headers.clone() : null;
  1705.     }

  1706.     /**
  1707.      * Gets a copy of the header comment array to write before the CSV data.
  1708.      * <p>
  1709.      * This setting is ignored by the parser.
  1710.      * </p>
  1711.      * <p>
  1712.      * Comments are printed first, before headers.
  1713.      * </p>
  1714.      * <p>
  1715.      * Use {@link Builder#setCommentMarker(char)} or {@link Builder#setCommentMarker(Character)} to set the comment marker written at the start of each comment
  1716.      * line.
  1717.      * </p>
  1718.      * <p>
  1719.      * If the comment marker is not set, then the header comments are ignored.
  1720.      * </p>
  1721.      * <p>
  1722.      * For example:
  1723.      * </p>
  1724.      *
  1725.      * <pre>
  1726.      * builder.setCommentMarker('#').setHeaderComments("Generated by Apache Commons CSV", Instant.ofEpochMilli(0));
  1727.      * </pre>
  1728.      * <p>
  1729.      * writes:
  1730.      * </p>
  1731.      *
  1732.      * <pre>
  1733.      * # Generated by Apache Commons CSV.
  1734.      * # 1970-01-01T00:00:00Z
  1735.      * </pre>
  1736.      *
  1737.      * @return a copy of the header comment array; {@code null} if disabled.
  1738.      */
  1739.     public String[] getHeaderComments() {
  1740.         return headerComments != null ? headerComments.clone() : null;
  1741.     }

  1742.     /**
  1743.      * Gets whether empty lines between records are ignored when parsing input.
  1744.      *
  1745.      * @return {@code true} if empty lines between records are ignored, {@code false} if they are turned into empty records.
  1746.      */
  1747.     public boolean getIgnoreEmptyLines() {
  1748.         return ignoreEmptyLines;
  1749.     }

  1750.     /**
  1751.      * Gets whether header names will be accessed ignoring case when parsing input.
  1752.      *
  1753.      * @return {@code true} if header names cases are ignored, {@code false} if they are case-sensitive.
  1754.      * @since 1.3
  1755.      */
  1756.     public boolean getIgnoreHeaderCase() {
  1757.         return ignoreHeaderCase;
  1758.     }

  1759.     /**
  1760.      * Gets whether spaces around values are ignored when parsing input.
  1761.      *
  1762.      * @return {@code true} if spaces around values are ignored, {@code false} if they are treated as part of the value.
  1763.      */
  1764.     public boolean getIgnoreSurroundingSpaces() {
  1765.         return ignoreSurroundingSpaces;
  1766.     }

  1767.     /**
  1768.      * Gets whether reading end-of-file is allowed even when input is malformed, helps Excel compatibility.
  1769.      *
  1770.      * @return whether reading end-of-file is allowed even when input is malformed, helps Excel compatibility.
  1771.      * @since 1.11.0
  1772.      */
  1773.     public boolean getLenientEof() {
  1774.         return lenientEof;
  1775.     }

  1776.     /**
  1777.      * Gets the maximum number of rows to process, excluding the header row.
  1778.      * <p>
  1779.      * Values less than or equal to 0 mean no limit.
  1780.      * </p>
  1781.      *
  1782.      * @return The maximum number of rows to process, excluding the header row.
  1783.      * @since 1.14.0
  1784.      */
  1785.     public long getMaxRows() {
  1786.         return maxRows;
  1787.     }

  1788.     /**
  1789.      * Gets the String to convert to and from {@code null}.
  1790.      * <ul>
  1791.      * <li><strong>Reading:</strong> Converts strings equal to the given {@code nullString} to {@code null} when reading records.</li>
  1792.      * <li><strong>Writing:</strong> Writes {@code null} as the given {@code nullString} when writing records.</li>
  1793.      * </ul>
  1794.      *
  1795.      * @return the String to convert to and from {@code null}. No substitution occurs if {@code null}
  1796.      */
  1797.     public String getNullString() {
  1798.         return nullString;
  1799.     }

  1800.     /**
  1801.      * Gets the character used to encapsulate values containing special characters.
  1802.      *
  1803.      * @return the quoteChar character, may be {@code null}
  1804.      */
  1805.     public Character getQuoteCharacter() {
  1806.         return quoteCharacter;
  1807.     }

  1808.     /**
  1809.      * Gets the quote policy output fields.
  1810.      *
  1811.      * @return the quote policy
  1812.      */
  1813.     public QuoteMode getQuoteMode() {
  1814.         return quoteMode;
  1815.     }

  1816.     /**
  1817.      * Gets the record separator delimiting output records.
  1818.      *
  1819.      * @return the record separator
  1820.      */
  1821.     public String getRecordSeparator() {
  1822.         return recordSeparator;
  1823.     }

  1824.     /**
  1825.      * Gets whether to skip the header record.
  1826.      *
  1827.      * @return whether to skip the header record.
  1828.      */
  1829.     public boolean getSkipHeaderRecord() {
  1830.         return skipHeaderRecord;
  1831.     }

  1832.     /**
  1833.      * Gets whether reading trailing data is allowed in records, helps Excel compatibility.
  1834.      *
  1835.      * @return whether reading trailing data is allowed in records, helps Excel compatibility.
  1836.      * @since 1.11.0
  1837.      */
  1838.     public boolean getTrailingData() {
  1839.         return trailingData;
  1840.     }

  1841.     /**
  1842.      * Gets whether to add a trailing delimiter.
  1843.      *
  1844.      * @return whether to add a trailing delimiter.
  1845.      * @since 1.3
  1846.      */
  1847.     public boolean getTrailingDelimiter() {
  1848.         return trailingDelimiter;
  1849.     }

  1850.     /**
  1851.      * Gets whether to trim leading and trailing blanks. This is used by {@link #print(Object, Appendable, boolean)} Also by {CSVParser#addRecordValue(boolean)}
  1852.      *
  1853.      * @return whether to trim leading and trailing blanks.
  1854.      */
  1855.     public boolean getTrim() {
  1856.         return trim;
  1857.     }

  1858.     @Override
  1859.     public int hashCode() {
  1860.         final int prime = 31;
  1861.         int result = 1;
  1862.         result = prime * result + Arrays.hashCode(headerComments);
  1863.         result = prime * result + Arrays.hashCode(headers);
  1864.         return prime * result + Objects.hash(allowMissingColumnNames, autoFlush, commentMarker, delimiter, duplicateHeaderMode, escapeCharacter,
  1865.                 ignoreEmptyLines, ignoreHeaderCase, ignoreSurroundingSpaces, lenientEof, nullString, quoteCharacter, quoteMode, quotedNullString,
  1866.                 recordSeparator, skipHeaderRecord, trailingData, trailingDelimiter, trim);
  1867.     }

  1868.     /**
  1869.      * Tests whether comments are supported by this format.
  1870.      *
  1871.      * Note that the comment introducer character is only recognized at the start of a line.
  1872.      *
  1873.      * @return {@code true} is comments are supported, {@code false} otherwise
  1874.      */
  1875.     public boolean isCommentMarkerSet() {
  1876.         return commentMarker != null;
  1877.     }

  1878.     /**
  1879.      * Tests whether the next characters constitute a delimiter
  1880.      *
  1881.      * @param ch0             the first char (index 0).
  1882.      * @param charSeq         the match char sequence
  1883.      * @param startIndex      where start to match
  1884.      * @param delimiter       the delimiter
  1885.      * @param delimiterLength the delimiter length
  1886.      * @return true if the match is successful
  1887.      */
  1888.     private boolean isDelimiter(final char ch0, final CharSequence charSeq, final int startIndex, final char[] delimiter, final int delimiterLength) {
  1889.         if (ch0 != delimiter[0]) {
  1890.             return false;
  1891.         }
  1892.         final int len = charSeq.length();
  1893.         if (startIndex + delimiterLength > len) {
  1894.             return false;
  1895.         }
  1896.         for (int i = 1; i < delimiterLength; i++) {
  1897.             if (charSeq.charAt(startIndex + i) != delimiter[i]) {
  1898.                 return false;
  1899.             }
  1900.         }
  1901.         return true;
  1902.     }

  1903.     /**
  1904.      * Tests whether escapes are being processed.
  1905.      *
  1906.      * @return {@code true} if escapes are processed
  1907.      */
  1908.     public boolean isEscapeCharacterSet() {
  1909.         return escapeCharacter != null;
  1910.     }

  1911.     /**
  1912.      * Tests whether a null string has been defined.
  1913.      *
  1914.      * @return {@code true} if a nullString is defined
  1915.      */
  1916.     public boolean isNullStringSet() {
  1917.         return nullString != null;
  1918.     }

  1919.     /**
  1920.      * Tests whether a quoteChar has been defined.
  1921.      *
  1922.      * @return {@code true} if a quoteChar is defined
  1923.      */
  1924.     public boolean isQuoteCharacterSet() {
  1925.         return quoteCharacter != null;
  1926.     }

  1927.     <T> IOStream<T> limit(final IOStream<T> stream) {
  1928.         return useMaxRows() ? stream.limit(getMaxRows()) : stream;
  1929.     }

  1930.     /**
  1931.      * Parses the specified content.
  1932.      *
  1933.      * <p>
  1934.      * See also the various static parse methods on {@link CSVParser}.
  1935.      * </p>
  1936.      *
  1937.      * @param reader the input stream
  1938.      * @return a parser over a stream of {@link CSVRecord}s.
  1939.      * @throws IOException  If an I/O error occurs
  1940.      * @throws CSVException Thrown on invalid input.
  1941.      */
  1942.     public CSVParser parse(final Reader reader) throws IOException {
  1943.         return CSVParser.builder().setReader(reader).setFormat(this).get();
  1944.     }

  1945.     /**
  1946.      * Prints to the specified output.
  1947.      *
  1948.      * <p>
  1949.      * See also {@link CSVPrinter}.
  1950.      * </p>
  1951.      *
  1952.      * @param out the output.
  1953.      * @return a printer to an output.
  1954.      * @throws IOException thrown if the optional header cannot be printed.
  1955.      */
  1956.     public CSVPrinter print(final Appendable out) throws IOException {
  1957.         return new CSVPrinter(out, this);
  1958.     }

  1959.     /**
  1960.      * Prints to the specified {@code File} with given {@code Charset}.
  1961.      *
  1962.      * <p>
  1963.      * See also {@link CSVPrinter}.
  1964.      * </p>
  1965.      *
  1966.      * @param out     the output.
  1967.      * @param charset A charset.
  1968.      * @return a printer to an output.
  1969.      * @throws IOException thrown if the optional header cannot be printed.
  1970.      * @since 1.5
  1971.      */
  1972.     public CSVPrinter print(final File out, final Charset charset) throws IOException {
  1973.         return print(out.toPath(), charset);
  1974.     }

  1975.     private void print(final InputStream inputStream, final Appendable out, final boolean newRecord) throws IOException {
  1976.         // InputStream is never null here
  1977.         // There is nothing to escape when quoting is used which is the default.
  1978.         if (!newRecord) {
  1979.             append(getDelimiterString(), out);
  1980.         }
  1981.         final boolean quoteCharacterSet = isQuoteCharacterSet();
  1982.         if (quoteCharacterSet) {
  1983.             append(getQuoteCharacter().charValue(), out); // Explicit (un)boxing is intentional
  1984.         }
  1985.         // Stream the input to the output without reading or holding the whole value in memory.
  1986.         // AppendableOutputStream cannot "close" an Appendable.
  1987.         try (OutputStream outputStream = new Base64OutputStream(new AppendableOutputStream<>(out))) {
  1988.             IOUtils.copy(inputStream, outputStream);
  1989.         }
  1990.         if (quoteCharacterSet) {
  1991.             append(getQuoteCharacter().charValue(), out); // Explicit (un)boxing is intentional
  1992.         }
  1993.     }

  1994.     /**
  1995.      * 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
  1996.      * avoid creating CSVPrinters. Trims the value if {@link #getTrim()} is true.
  1997.      *
  1998.      * @param value     value to output.
  1999.      * @param out       where to print the value.
  2000.      * @param newRecord if this a new record.
  2001.      * @throws IOException If an I/O error occurs.
  2002.      * @since 1.4
  2003.      */
  2004.     public synchronized void print(final Object value, final Appendable out, final boolean newRecord) throws IOException {
  2005.         // null values are considered empty
  2006.         // Only call CharSequence.toString() if you have to, helps GC-free use cases.
  2007.         CharSequence charSequence;
  2008.         if (value == null) {
  2009.             // https://issues.apache.org/jira/browse/CSV-203
  2010.             if (null == nullString) {
  2011.                 charSequence = Constants.EMPTY;
  2012.             } else if (QuoteMode.ALL == quoteMode) {
  2013.                 charSequence = quotedNullString;
  2014.             } else {
  2015.                 charSequence = nullString;
  2016.             }
  2017.         } else if (value instanceof CharSequence) {
  2018.             charSequence = (CharSequence) value;
  2019.         } else if (value instanceof Reader) {
  2020.             print((Reader) value, out, newRecord);
  2021.             return;
  2022.         } else if (value instanceof InputStream) {
  2023.             print((InputStream) value, out, newRecord);
  2024.             return;
  2025.         } else {
  2026.             charSequence = value.toString();
  2027.         }
  2028.         charSequence = getTrim() ? trim(charSequence) : charSequence;
  2029.         print(value, charSequence, out, newRecord);
  2030.     }

  2031.     private synchronized void print(final Object object, final CharSequence value, final Appendable out, final boolean newRecord) throws IOException {
  2032.         final int offset = 0;
  2033.         final int len = value.length();
  2034.         if (!newRecord) {
  2035.             out.append(getDelimiterString());
  2036.         }
  2037.         if (object == null) {
  2038.             out.append(value);
  2039.         } else if (isQuoteCharacterSet()) {
  2040.             // The original object is needed so can check for Number
  2041.             printWithQuotes(object, value, out, newRecord);
  2042.         } else if (isEscapeCharacterSet()) {
  2043.             printWithEscapes(value, out);
  2044.         } else {
  2045.             out.append(value, offset, len);
  2046.         }
  2047.     }

  2048.     /**
  2049.      * Prints to the specified {@code Path} with given {@code Charset}, returns a {@code CSVPrinter} which the caller MUST close.
  2050.      *
  2051.      * <p>
  2052.      * See also {@link CSVPrinter}.
  2053.      * </p>
  2054.      *
  2055.      * @param out     the output.
  2056.      * @param charset A charset.
  2057.      * @return a printer to an output.
  2058.      * @throws IOException thrown if the optional header cannot be printed.
  2059.      * @since 1.5
  2060.      */
  2061.     @SuppressWarnings("resource")
  2062.     public CSVPrinter print(final Path out, final Charset charset) throws IOException {
  2063.         return print(Files.newBufferedWriter(out, charset));
  2064.     }

  2065.     private void print(final Reader reader, final Appendable out, final boolean newRecord) throws IOException {
  2066.         // Reader is never null here
  2067.         if (!newRecord) {
  2068.             append(getDelimiterString(), out);
  2069.         }
  2070.         if (isQuoteCharacterSet()) {
  2071.             printWithQuotes(reader, out);
  2072.         } else if (isEscapeCharacterSet()) {
  2073.             printWithEscapes(reader, out);
  2074.         } else if (out instanceof Writer) {
  2075.             IOUtils.copyLarge(reader, (Writer) out);
  2076.         } else {
  2077.             IOUtils.copy(reader, out);
  2078.         }
  2079.     }

  2080.     /**
  2081.      * Prints to the {@link System#out}.
  2082.      *
  2083.      * <p>
  2084.      * See also {@link CSVPrinter}.
  2085.      * </p>
  2086.      *
  2087.      * @return a printer to {@link System#out}.
  2088.      * @throws IOException thrown if the optional header cannot be printed.
  2089.      * @since 1.5
  2090.      */
  2091.     public CSVPrinter printer() throws IOException {
  2092.         return new CSVPrinter(System.out, this);
  2093.     }

  2094.     /**
  2095.      * Outputs the trailing delimiter (if set) followed by the record separator (if set).
  2096.      *
  2097.      * @param appendable where to write
  2098.      * @throws IOException If an I/O error occurs.
  2099.      * @since 1.4
  2100.      */
  2101.     public synchronized void println(final Appendable appendable) throws IOException {
  2102.         if (getTrailingDelimiter()) {
  2103.             append(getDelimiterString(), appendable);
  2104.         }
  2105.         if (recordSeparator != null) {
  2106.             append(recordSeparator, appendable);
  2107.         }
  2108.     }

  2109.     /**
  2110.      * Prints the given {@code values} to {@code out} as a single record of delimiter-separated values followed by the record separator.
  2111.      *
  2112.      * <p>
  2113.      * 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
  2114.      * the record, so there is no need to call {@link #println(Appendable)}.
  2115.      * </p>
  2116.      *
  2117.      * @param appendable where to write.
  2118.      * @param values     values to output.
  2119.      * @throws IOException If an I/O error occurs.
  2120.      * @since 1.4
  2121.      */
  2122.     public synchronized void printRecord(final Appendable appendable, final Object... values) throws IOException {
  2123.         for (int i = 0; i < values.length; i++) {
  2124.             print(values[i], appendable, i == 0);
  2125.         }
  2126.         println(appendable);
  2127.     }

  2128.     /*
  2129.      * This method must only be called if escaping is enabled, otherwise can throw exceptions.
  2130.      */
  2131.     private void printWithEscapes(final CharSequence charSeq, final Appendable appendable) throws IOException {
  2132.         int start = 0;
  2133.         int pos = 0;
  2134.         final int end = charSeq.length();
  2135.         final char[] delimArray = getDelimiterCharArray();
  2136.         final int delimLength = delimArray.length;
  2137.         final char escape = getEscapeChar();
  2138.         while (pos < end) {
  2139.             char c = charSeq.charAt(pos);
  2140.             final boolean isDelimiterStart = isDelimiter(c, charSeq, pos, delimArray, delimLength);
  2141.             final boolean isCr = c == Constants.CR;
  2142.             final boolean isLf = c == Constants.LF;
  2143.             if (isCr || isLf || c == escape || isDelimiterStart) {
  2144.                 // write out segment up until this char
  2145.                 if (pos > start) {
  2146.                     appendable.append(charSeq, start, pos);
  2147.                 }
  2148.                 if (isLf) {
  2149.                     c = 'n';
  2150.                 } else if (isCr) {
  2151.                     c = 'r';
  2152.                 }
  2153.                 escape(c, appendable);
  2154.                 if (isDelimiterStart) {
  2155.                     for (int i = 1; i < delimLength; i++) {
  2156.                         pos++;
  2157.                         escape(charSeq.charAt(pos), appendable);
  2158.                     }
  2159.                 }
  2160.                 start = pos + 1; // start on the current char after this one
  2161.             }
  2162.             pos++;
  2163.         }

  2164.         // write last segment
  2165.         if (pos > start) {
  2166.             appendable.append(charSeq, start, pos);
  2167.         }
  2168.     }

  2169.     /*
  2170.      * This method must only be called if escaping is enabled, otherwise can throw exceptions.
  2171.      */
  2172.     private void printWithEscapes(final Reader reader, final Appendable appendable) throws IOException {
  2173.         int start = 0;
  2174.         int pos = 0;
  2175.         @SuppressWarnings("resource") // Temp reader on input reader.
  2176.         final ExtendedBufferedReader bufferedReader = new ExtendedBufferedReader(reader);
  2177.         final char[] delimArray = getDelimiterCharArray();
  2178.         final int delimLength = delimArray.length;
  2179.         final char escape = getEscapeChar();
  2180.         final StringBuilder builder = new StringBuilder(IOUtils.DEFAULT_BUFFER_SIZE);
  2181.         int c;
  2182.         final char[] lookAheadBuffer = new char[delimLength - 1];
  2183.         while (EOF != (c = bufferedReader.read())) {
  2184.             builder.append((char) c);
  2185.             Arrays.fill(lookAheadBuffer, (char) 0);
  2186.             bufferedReader.peek(lookAheadBuffer);
  2187.             final String test = builder.toString() + new String(lookAheadBuffer);
  2188.             final boolean isDelimiterStart = isDelimiter((char) c, test, pos, delimArray, delimLength);
  2189.             final boolean isCr = c == Constants.CR;
  2190.             final boolean isLf = c == Constants.LF;
  2191.             if (isCr || isLf || c == escape || isDelimiterStart) {
  2192.                 // write out segment up until this char
  2193.                 if (pos > start) {
  2194.                     append(builder.substring(start, pos), appendable);
  2195.                     builder.setLength(0);
  2196.                     pos = -1;
  2197.                 }
  2198.                 if (isLf) {
  2199.                     c = 'n';
  2200.                 } else if (isCr) {
  2201.                     c = 'r';
  2202.                 }
  2203.                 escape((char) c, appendable);
  2204.                 if (isDelimiterStart) {
  2205.                     for (int i = 1; i < delimLength; i++) {
  2206.                         escape((char) bufferedReader.read(), appendable);
  2207.                     }
  2208.                 }
  2209.                 start = pos + 1; // start on the current char after this one
  2210.             }
  2211.             pos++;
  2212.         }
  2213.         // write last segment
  2214.         if (pos > start) {
  2215.             appendable.append(builder, start, pos);
  2216.         }
  2217.     }

  2218.     /*
  2219.      * This method must only be called if quoting is enabled, otherwise will generate NPE.
  2220.      * The original object is needed so can check for Number
  2221.      */
  2222.     private void printWithQuotes(final Object object, final CharSequence charSeq, final Appendable out, final boolean newRecord) throws IOException {
  2223.         boolean quote = false;
  2224.         int start = 0;
  2225.         int pos = 0;
  2226.         final int len = charSeq.length();
  2227.         final char[] delim = getDelimiterCharArray();
  2228.         final int delimLength = delim.length;
  2229.         final char quoteChar = getQuoteCharacter().charValue(); // Explicit (un)boxing is intentional
  2230.         // If escape char not specified, default to the quote char
  2231.         // This avoids having to keep checking whether there is an escape character
  2232.         // at the cost of checking against quote twice
  2233.         final char escapeChar = isEscapeCharacterSet() ? getEscapeChar() : quoteChar;
  2234.         QuoteMode quoteModePolicy = getQuoteMode();
  2235.         if (quoteModePolicy == null) {
  2236.             quoteModePolicy = QuoteMode.MINIMAL;
  2237.         }
  2238.         switch (quoteModePolicy) {
  2239.         case ALL:
  2240.         case ALL_NON_NULL:
  2241.             quote = true;
  2242.             break;
  2243.         case NON_NUMERIC:
  2244.             quote = !(object instanceof Number);
  2245.             break;
  2246.         case NONE:
  2247.             // Use the existing escaping code
  2248.             printWithEscapes(charSeq, out);
  2249.             return;
  2250.         case MINIMAL:
  2251.             if (len <= 0) {
  2252.                 // Always quote an empty token that is the first
  2253.                 // on the line, as it may be the only thing on the
  2254.                 // line. If it were not quoted in that case,
  2255.                 // an empty line has no tokens.
  2256.                 if (newRecord) {
  2257.                     quote = true;
  2258.                 }
  2259.             } else {
  2260.                 char c = charSeq.charAt(pos);
  2261.                 if (c <= Constants.COMMENT) {
  2262.                     // Some other chars at the start of a value caused the parser to fail, so for now
  2263.                     // encapsulate if we start in anything less than '#'. We are being conservative
  2264.                     // by including the default comment char too.
  2265.                     quote = true;
  2266.                 } else {
  2267.                     while (pos < len) {
  2268.                         c = charSeq.charAt(pos);
  2269.                         if (c == Constants.LF || c == Constants.CR || c == quoteChar || c == escapeChar || isDelimiter(c, charSeq, pos, delim, delimLength)) {
  2270.                             quote = true;
  2271.                             break;
  2272.                         }
  2273.                         pos++;
  2274.                     }

  2275.                     if (!quote) {
  2276.                         pos = len - 1;
  2277.                         c = charSeq.charAt(pos);
  2278.                         // Some other chars at the end caused the parser to fail, so for now
  2279.                         // encapsulate if we end in anything less than ' '
  2280.                         if (isTrimChar(c)) {
  2281.                             quote = true;
  2282.                         }
  2283.                     }
  2284.                 }
  2285.             }
  2286.             if (!quote) {
  2287.                 // No encapsulation needed - write out the original value
  2288.                 out.append(charSeq, start, len);
  2289.                 return;
  2290.             }
  2291.             break;
  2292.         default:
  2293.             throw new IllegalStateException("Unexpected Quote value: " + quoteModePolicy);
  2294.         }
  2295.         if (!quote) {
  2296.             // No encapsulation needed - write out the original value
  2297.             out.append(charSeq, start, len);
  2298.             return;
  2299.         }
  2300.         // We hit something that needed encapsulation
  2301.         out.append(quoteChar);
  2302.         // Pick up where we left off: pos should be positioned on the first character that caused
  2303.         // the need for encapsulation.
  2304.         while (pos < len) {
  2305.             final char c = charSeq.charAt(pos);
  2306.             if (c == quoteChar || c == escapeChar) {
  2307.                 // write out the chunk up until this point
  2308.                 out.append(charSeq, start, pos);
  2309.                 out.append(escapeChar); // now output the escape
  2310.                 start = pos; // and restart with the matched char
  2311.             }
  2312.             pos++;
  2313.         }
  2314.         // Write the last segment
  2315.         out.append(charSeq, start, pos);
  2316.         out.append(quoteChar);
  2317.     }

  2318.     /**
  2319.      * Always use quotes unless QuoteMode is NONE, so we do not have to look ahead.
  2320.      *
  2321.      * @param reader     What to print
  2322.      * @param appendable Where to print it
  2323.      * @throws IOException If an I/O error occurs
  2324.      */
  2325.     private void printWithQuotes(final Reader reader, final Appendable appendable) throws IOException {
  2326.         if (getQuoteMode() == QuoteMode.NONE) {
  2327.             printWithEscapes(reader, appendable);
  2328.             return;
  2329.         }
  2330.         final char quote = getQuoteCharacter().charValue(); // Explicit (un)boxing is intentional
  2331.         // (1) Append opening quote
  2332.         append(quote, appendable);
  2333.         // (2) Append Reader contents, doubling quotes
  2334.         int c;
  2335.         while (EOF != (c = reader.read())) {
  2336.             append((char) c, appendable);
  2337.             if (c == quote) {
  2338.                 append(quote, appendable);
  2339.             }
  2340.         }
  2341.         // (3) Append closing quote
  2342.         append(quote, appendable);
  2343.     }

  2344.     @Override
  2345.     public String toString() {
  2346.         final StringBuilder sb = new StringBuilder();
  2347.         sb.append("Delimiter=<").append(delimiter).append('>');
  2348.         if (isEscapeCharacterSet()) {
  2349.             sb.append(' ');
  2350.             sb.append("Escape=<").append(escapeCharacter).append('>');
  2351.         }
  2352.         if (isQuoteCharacterSet()) {
  2353.             sb.append(' ');
  2354.             sb.append("QuoteChar=<").append(quoteCharacter).append('>');
  2355.         }
  2356.         if (quoteMode != null) {
  2357.             sb.append(' ');
  2358.             sb.append("QuoteMode=<").append(quoteMode).append('>');
  2359.         }
  2360.         if (isCommentMarkerSet()) {
  2361.             sb.append(' ');
  2362.             sb.append("CommentStart=<").append(commentMarker).append('>');
  2363.         }
  2364.         if (isNullStringSet()) {
  2365.             sb.append(' ');
  2366.             sb.append("NullString=<").append(nullString).append('>');
  2367.         }
  2368.         if (recordSeparator != null) {
  2369.             sb.append(' ');
  2370.             sb.append("RecordSeparator=<").append(recordSeparator).append('>');
  2371.         }
  2372.         if (getIgnoreEmptyLines()) {
  2373.             sb.append(" EmptyLines:ignored");
  2374.         }
  2375.         if (getIgnoreSurroundingSpaces()) {
  2376.             sb.append(" SurroundingSpaces:ignored");
  2377.         }
  2378.         if (getIgnoreHeaderCase()) {
  2379.             sb.append(" IgnoreHeaderCase:ignored");
  2380.         }
  2381.         sb.append(" SkipHeaderRecord:").append(skipHeaderRecord);
  2382.         if (headerComments != null) {
  2383.             sb.append(' ');
  2384.             sb.append("HeaderComments:").append(Arrays.toString(headerComments));
  2385.         }
  2386.         if (headers != null) {
  2387.             sb.append(' ');
  2388.             sb.append("Header:").append(Arrays.toString(headers));
  2389.         }
  2390.         return sb.toString();
  2391.     }

  2392.     String trim(final String value) {
  2393.         return getTrim() ? value.trim() : value;
  2394.     }

  2395.     boolean useMaxRows() {
  2396.         return getMaxRows() > 0;
  2397.     }

  2398.     boolean useRow(final long rowNum) {
  2399.         return !useMaxRows() || rowNum <= getMaxRows();
  2400.     }

  2401.     /**
  2402.      * Verifies the validity and consistency of the attributes, and throws an {@link IllegalArgumentException} if necessary.
  2403.      * <p>
  2404.      * Because an instance can be used for both writing and parsing, not all conditions can be tested here. For example, allowMissingColumnNames is only used
  2405.      * for parsing, so it cannot be used here.
  2406.      * </p>
  2407.      *
  2408.      * @throws IllegalArgumentException Throw when any attribute is invalid or inconsistent with other attributes.
  2409.      */
  2410.     private void validate() throws IllegalArgumentException {
  2411.         if (quoteCharacter != null && contains(delimiter, quoteCharacter.charValue())) { // Explicit (un)boxing is intentional
  2412.             throw new IllegalArgumentException("The quoteChar character and the delimiter cannot be the same ('" + quoteCharacter + "')");
  2413.         }
  2414.         if (escapeCharacter != null && contains(delimiter, escapeCharacter.charValue())) { // Explicit (un)boxing is intentional
  2415.             throw new IllegalArgumentException("The escape character and the delimiter cannot be the same ('" + escapeCharacter + "')");
  2416.         }
  2417.         if (commentMarker != null && contains(delimiter, commentMarker.charValue())) { // Explicit (un)boxing is intentional
  2418.             throw new IllegalArgumentException("The comment start character and the delimiter cannot be the same ('" + commentMarker + "')");
  2419.         }
  2420.         if (quoteCharacter != null && quoteCharacter.equals(commentMarker)) {
  2421.             throw new IllegalArgumentException("The comment start character and the quoteChar cannot be the same ('" + commentMarker + "')");
  2422.         }
  2423.         if (escapeCharacter != null && escapeCharacter.equals(commentMarker)) {
  2424.             throw new IllegalArgumentException("The comment start and the escape character cannot be the same ('" + commentMarker + "')");
  2425.         }
  2426.         if (escapeCharacter == null && quoteMode == QuoteMode.NONE) {
  2427.             throw new IllegalArgumentException("Quote mode set to NONE but no escape character is set");
  2428.         }
  2429.         // Validate headers
  2430.         if (headers != null && duplicateHeaderMode != DuplicateHeaderMode.ALLOW_ALL) {
  2431.             final Set<String> dupCheckSet = new HashSet<>(headers.length);
  2432.             final boolean emptyDuplicatesAllowed = duplicateHeaderMode == DuplicateHeaderMode.ALLOW_EMPTY;
  2433.             for (final String header : headers) {
  2434.                 final boolean blank = isBlank(header);
  2435.                 // Sanitize all empty headers to the empty string "" when checking duplicates
  2436.                 final boolean containsHeader = !dupCheckSet.add(blank ? "" : header);
  2437.                 if (containsHeader && !(blank && emptyDuplicatesAllowed)) {
  2438.                     throw new IllegalArgumentException(String.format(
  2439.                             "The header contains a duplicate name: \"%s\" in %s. If this is valid then use CSVFormat.Builder.setDuplicateHeaderMode().", header,
  2440.                             Arrays.toString(headers)));
  2441.                 }
  2442.             }
  2443.         }
  2444.     }

  2445.     /**
  2446.      * Builds a new {@code CSVFormat} that allows duplicate header names.
  2447.      *
  2448.      * @return a new {@code CSVFormat} that allows duplicate header names
  2449.      * @since 1.7
  2450.      * @deprecated Use {@link Builder#setAllowDuplicateHeaderNames(boolean) Builder#setAllowDuplicateHeaderNames(true)}
  2451.      */
  2452.     @Deprecated
  2453.     public CSVFormat withAllowDuplicateHeaderNames() {
  2454.         return builder().setDuplicateHeaderMode(DuplicateHeaderMode.ALLOW_ALL).get();
  2455.     }

  2456.     /**
  2457.      * Builds a new {@code CSVFormat} with duplicate header names behavior set to the given value.
  2458.      *
  2459.      * @param allowDuplicateHeaderNames the duplicate header names behavior, true to allow, false to disallow.
  2460.      * @return a new {@code CSVFormat} with duplicate header names behavior set to the given value.
  2461.      * @since 1.7
  2462.      * @deprecated Use {@link Builder#setAllowDuplicateHeaderNames(boolean)}
  2463.      */
  2464.     @Deprecated
  2465.     public CSVFormat withAllowDuplicateHeaderNames(final boolean allowDuplicateHeaderNames) {
  2466.         final DuplicateHeaderMode mode = allowDuplicateHeaderNames ? DuplicateHeaderMode.ALLOW_ALL : DuplicateHeaderMode.ALLOW_EMPTY;
  2467.         return builder().setDuplicateHeaderMode(mode).get();
  2468.     }

  2469.     /**
  2470.      * Builds a new {@code CSVFormat} with the missing column names behavior of the format set to {@code true}.
  2471.      *
  2472.      * @return A new CSVFormat that is equal to this but with the specified missing column names behavior.
  2473.      * @see Builder#setAllowMissingColumnNames(boolean)
  2474.      * @since 1.1
  2475.      * @deprecated Use {@link Builder#setAllowMissingColumnNames(boolean) Builder#setAllowMissingColumnNames(true)}
  2476.      */
  2477.     @Deprecated
  2478.     public CSVFormat withAllowMissingColumnNames() {
  2479.         return builder().setAllowMissingColumnNames(true).get();
  2480.     }

  2481.     /**
  2482.      * Builds a new {@code CSVFormat} with the missing column names behavior of the format set to the given value.
  2483.      *
  2484.      * @param allowMissingColumnNames the missing column names behavior, {@code true} to allow missing column names in the header line, {@code false} to cause
  2485.      *                                an {@link IllegalArgumentException} to be thrown.
  2486.      * @return A new CSVFormat that is equal to this but with the specified missing column names behavior.
  2487.      * @deprecated Use {@link Builder#setAllowMissingColumnNames(boolean)}
  2488.      */
  2489.     @Deprecated
  2490.     public CSVFormat withAllowMissingColumnNames(final boolean allowMissingColumnNames) {
  2491.         return builder().setAllowMissingColumnNames(allowMissingColumnNames).get();
  2492.     }

  2493.     /**
  2494.      * Builds a new {@code CSVFormat} with whether to flush on close.
  2495.      *
  2496.      * @param autoFlush whether to flush on close.
  2497.      * @return A new CSVFormat that is equal to this but with the specified autoFlush setting.
  2498.      * @since 1.6
  2499.      * @deprecated Use {@link Builder#setAutoFlush(boolean)}
  2500.      */
  2501.     @Deprecated
  2502.     public CSVFormat withAutoFlush(final boolean autoFlush) {
  2503.         return builder().setAutoFlush(autoFlush).get();
  2504.     }

  2505.     /**
  2506.      * Builds a new {@code CSVFormat} with the comment start marker of the format set to the specified character.
  2507.      *
  2508.      * Note that the comment start character is only recognized at the start of a line.
  2509.      *
  2510.      * @param commentMarker the comment start marker
  2511.      * @return A new CSVFormat that is equal to this one but with the specified character as the comment start marker
  2512.      * @throws IllegalArgumentException thrown if the specified character is a line break
  2513.      * @deprecated Use {@link Builder#setCommentMarker(char)}
  2514.      */
  2515.     @Deprecated
  2516.     public CSVFormat withCommentMarker(final char commentMarker) {
  2517.         return builder().setCommentMarker(commentMarker).get();
  2518.     }

  2519.     /**
  2520.      * Builds a new {@code CSVFormat} with the comment start marker of the format set to the specified character.
  2521.      *
  2522.      * Note that the comment start character is only recognized at the start of a line.
  2523.      *
  2524.      * @param commentMarker the comment start marker, use {@code null} to disable
  2525.      * @return A new CSVFormat that is equal to this one but with the specified character as the comment start marker
  2526.      * @throws IllegalArgumentException thrown if the specified character is a line break
  2527.      * @deprecated Use {@link Builder#setCommentMarker(Character)}
  2528.      */
  2529.     @Deprecated
  2530.     public CSVFormat withCommentMarker(final Character commentMarker) {
  2531.         return builder().setCommentMarker(commentMarker).get();
  2532.     }

  2533.     /**
  2534.      * Builds a new {@code CSVFormat} with the delimiter of the format set to the specified character.
  2535.      *
  2536.      * @param delimiter the delimiter character
  2537.      * @return A new CSVFormat that is equal to this with the specified character as a delimiter
  2538.      * @throws IllegalArgumentException thrown if the specified character is a line break
  2539.      * @deprecated Use {@link Builder#setDelimiter(char)}
  2540.      */
  2541.     @Deprecated
  2542.     public CSVFormat withDelimiter(final char delimiter) {
  2543.         return builder().setDelimiter(delimiter).get();
  2544.     }

  2545.     /**
  2546.      * Builds a new {@code CSVFormat} with the escape character of the format set to the specified character.
  2547.      *
  2548.      * @param escape the escape character
  2549.      * @return A new CSVFormat that is equal to this but with the specified character as the escape character
  2550.      * @throws IllegalArgumentException thrown if the specified character is a line break
  2551.      * @deprecated Use {@link Builder#setEscape(char)}
  2552.      */
  2553.     @Deprecated
  2554.     public CSVFormat withEscape(final char escape) {
  2555.         return builder().setEscape(escape).get();
  2556.     }

  2557.     /**
  2558.      * Builds a new {@code CSVFormat} with the escape character of the format set to the specified character.
  2559.      *
  2560.      * @param escape the escape character, use {@code null} to disable
  2561.      * @return A new CSVFormat that is equal to this but with the specified character as the escape character
  2562.      * @throws IllegalArgumentException thrown if the specified character is a line break
  2563.      * @deprecated Use {@link Builder#setEscape(Character)}
  2564.      */
  2565.     @Deprecated
  2566.     public CSVFormat withEscape(final Character escape) {
  2567.         return builder().setEscape(escape).get();
  2568.     }

  2569.     // @formatter:off
  2570.     /**
  2571.      * Builds a new {@code CSVFormat} using the first record as header.
  2572.      *
  2573.      * <p>
  2574.      * Calling this method is equivalent to calling:
  2575.      * </p>
  2576.      *
  2577.      * <pre>
  2578.      * CSVFormat format = aFormat.builder()
  2579.      *                           .setHeader()
  2580.      *                           .setSkipHeaderRecord(true)
  2581.      *                           .get();
  2582.      * </pre>
  2583.      *
  2584.      * @return A new CSVFormat that is equal to this but using the first record as header.
  2585.      * @see Builder#setSkipHeaderRecord(boolean)
  2586.      * @see Builder#setHeader(String...)
  2587.      * @since 1.3
  2588.      * @deprecated Use {@link Builder#setHeader(String...) Builder#setHeader()}.{@link Builder#setSkipHeaderRecord(boolean) setSkipHeaderRecord(true)}.
  2589.      */
  2590.     // @formatter:on
  2591.     @Deprecated
  2592.     public CSVFormat withFirstRecordAsHeader() {
  2593.         // @formatter:off
  2594.         return builder()
  2595.                 .setHeader()
  2596.                 .setSkipHeaderRecord(true)
  2597.                 .get();
  2598.         // @formatter:on
  2599.     }

  2600.     /**
  2601.      * Builds a new {@code CSVFormat} with the header of the format defined by the enum class.
  2602.      *
  2603.      * <p>
  2604.      * Example:
  2605.      * </p>
  2606.      *
  2607.      * <pre>
  2608.      * public enum MyHeader {
  2609.      *     Name, Email, Phone
  2610.      * }
  2611.      * ...
  2612.      * CSVFormat format = aFormat.builder().setHeader(MyHeader.class).get();
  2613.      * </pre>
  2614.      * <p>
  2615.      * The header is also used by the {@link CSVPrinter}.
  2616.      * </p>
  2617.      *
  2618.      * @param headerEnum the enum defining the header, {@code null} if disabled, empty if parsed automatically, user specified otherwise.
  2619.      * @return A new CSVFormat that is equal to this but with the specified header
  2620.      * @see Builder#setHeader(String...)
  2621.      * @see Builder#setSkipHeaderRecord(boolean)
  2622.      * @since 1.3
  2623.      * @deprecated Use {@link Builder#setHeader(Class)}
  2624.      */
  2625.     @Deprecated
  2626.     public CSVFormat withHeader(final Class<? extends Enum<?>> headerEnum) {
  2627.         return builder().setHeader(headerEnum).get();
  2628.     }

  2629.     /**
  2630.      * 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
  2631.      * input file with:
  2632.      *
  2633.      * <pre>
  2634.      * CSVFormat format = aFormat.builder().setHeader().get();
  2635.      * </pre>
  2636.      *
  2637.      * or specified manually with:
  2638.      *
  2639.      * <pre>
  2640.      * CSVFormat format = aFormat.builder().setHeader(resultSet).get();
  2641.      * </pre>
  2642.      * <p>
  2643.      * The header is also used by the {@link CSVPrinter}.
  2644.      * </p>
  2645.      *
  2646.      * @param resultSet the resultSet for the header, {@code null} if disabled, empty if parsed automatically, user-specified otherwise.
  2647.      * @return A new CSVFormat that is equal to this but with the specified header
  2648.      * @throws SQLException SQLException if a database access error occurs or this method is called on a closed result set.
  2649.      * @since 1.1
  2650.      * @deprecated Use {@link Builder#setHeader(ResultSet)}
  2651.      */
  2652.     @Deprecated
  2653.     public CSVFormat withHeader(final ResultSet resultSet) throws SQLException {
  2654.         return builder().setHeader(resultSet).get();
  2655.     }

  2656.     /**
  2657.      * 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
  2658.      * input file with:
  2659.      *
  2660.      * <pre>
  2661.      * CSVFormat format = aFormat.builder().setHeader().get()
  2662.      * </pre>
  2663.      *
  2664.      * or specified manually with:
  2665.      *
  2666.      * <pre>
  2667.      * CSVFormat format = aFormat.builder().setHeader(resultSetMetaData).get()
  2668.      * </pre>
  2669.      * <p>
  2670.      * The header is also used by the {@link CSVPrinter}.
  2671.      * </p>
  2672.      *
  2673.      * @param resultSetMetaData the metaData for the header, {@code null} if disabled, empty if parsed automatically, user specified otherwise.
  2674.      * @return A new CSVFormat that is equal to this but with the specified header
  2675.      * @throws SQLException SQLException if a database access error occurs or this method is called on a closed result set.
  2676.      * @since 1.1
  2677.      * @deprecated Use {@link Builder#setHeader(ResultSetMetaData)}
  2678.      */
  2679.     @Deprecated
  2680.     public CSVFormat withHeader(final ResultSetMetaData resultSetMetaData) throws SQLException {
  2681.         return builder().setHeader(resultSetMetaData).get();
  2682.     }

  2683.     /**
  2684.      * 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
  2685.      * with:
  2686.      *
  2687.      * <pre>
  2688.      * CSVFormat format = aFormat.builder().setHeader().get();
  2689.      * </pre>
  2690.      *
  2691.      * or specified manually with:
  2692.      *
  2693.      * <pre>{@code
  2694.      * CSVFormat format = aFormat.builder().setHeader("name", "email", "phone").get();
  2695.      * }</pre>
  2696.      * <p>
  2697.      * The header is also used by the {@link CSVPrinter}.
  2698.      * </p>
  2699.      *
  2700.      * @param header the header, {@code null} if disabled, empty if parsed automatically, user-specified otherwise.
  2701.      * @return A new CSVFormat that is equal to this but with the specified header
  2702.      * @see Builder#setSkipHeaderRecord(boolean)
  2703.      * @deprecated Use {@link Builder#setHeader(String...)}
  2704.      */
  2705.     @Deprecated
  2706.     public CSVFormat withHeader(final String... header) {
  2707.         return builder().setHeader(header).get();
  2708.     }

  2709.     /**
  2710.      * 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.
  2711.      * This setting is ignored by the parser.
  2712.      *
  2713.      * <pre>{@code
  2714.      * CSVFormat format = aFormat.builder().setHeaderComments("Generated by Apache Commons CSV.", Instant.now()).get();
  2715.      * }</pre>
  2716.      *
  2717.      * @param headerComments the headerComments which will be printed by the Printer before the actual CSV data.
  2718.      * @return A new CSVFormat that is equal to this but with the specified header
  2719.      * @see Builder#setSkipHeaderRecord(boolean)
  2720.      * @since 1.1
  2721.      * @deprecated Use {@link Builder#setHeaderComments(Object...)}
  2722.      */
  2723.     @Deprecated
  2724.     public CSVFormat withHeaderComments(final Object... headerComments) {
  2725.         return builder().setHeaderComments(headerComments).get();
  2726.     }

  2727.     /**
  2728.      * Builds a new {@code CSVFormat} with the empty line skipping behavior of the format set to {@code true}.
  2729.      *
  2730.      * @return A new CSVFormat that is equal to this but with the specified empty line skipping behavior.
  2731.      * @see Builder#setIgnoreEmptyLines(boolean)
  2732.      * @since 1.1
  2733.      * @deprecated Use {@link Builder#setIgnoreEmptyLines(boolean) Builder#setIgnoreEmptyLines(true)}
  2734.      */
  2735.     @Deprecated
  2736.     public CSVFormat withIgnoreEmptyLines() {
  2737.         return builder().setIgnoreEmptyLines(true).get();
  2738.     }

  2739.     /**
  2740.      * Builds a new {@code CSVFormat} with the empty line skipping behavior of the format set to the given value.
  2741.      *
  2742.      * @param ignoreEmptyLines the empty line skipping behavior, {@code true} to ignore the empty lines between the records, {@code false} to translate empty
  2743.      *                         lines to empty records.
  2744.      * @return A new CSVFormat that is equal to this but with the specified empty line skipping behavior.
  2745.      * @deprecated Use {@link Builder#setIgnoreEmptyLines(boolean)}
  2746.      */
  2747.     @Deprecated
  2748.     public CSVFormat withIgnoreEmptyLines(final boolean ignoreEmptyLines) {
  2749.         return builder().setIgnoreEmptyLines(ignoreEmptyLines).get();
  2750.     }

  2751.     /**
  2752.      * Builds a new {@code CSVFormat} with the header ignore case behavior set to {@code true}.
  2753.      *
  2754.      * @return A new CSVFormat that will ignore the new case header name behavior.
  2755.      * @see Builder#setIgnoreHeaderCase(boolean)
  2756.      * @since 1.3
  2757.      * @deprecated Use {@link Builder#setIgnoreHeaderCase(boolean) Builder#setIgnoreHeaderCase(true)}
  2758.      */
  2759.     @Deprecated
  2760.     public CSVFormat withIgnoreHeaderCase() {
  2761.         return builder().setIgnoreHeaderCase(true).get();
  2762.     }

  2763.     /**
  2764.      * Builds a new {@code CSVFormat} with whether header names should be accessed ignoring case.
  2765.      *
  2766.      * @param ignoreHeaderCase the case mapping behavior, {@code true} to access name/values, {@code false} to leave the mapping as is.
  2767.      * @return A new CSVFormat that will ignore case header name if specified as {@code true}
  2768.      * @since 1.3
  2769.      * @deprecated Use {@link Builder#setIgnoreHeaderCase(boolean)}
  2770.      */
  2771.     @Deprecated
  2772.     public CSVFormat withIgnoreHeaderCase(final boolean ignoreHeaderCase) {
  2773.         return builder().setIgnoreHeaderCase(ignoreHeaderCase).get();
  2774.     }

  2775.     /**
  2776.      * Builds a new {@code CSVFormat} with the parser trimming behavior of the format set to {@code true}.
  2777.      *
  2778.      * @return A new CSVFormat that is equal to this but with the specified parser trimming behavior.
  2779.      * @see Builder#setIgnoreSurroundingSpaces(boolean)
  2780.      * @since 1.1
  2781.      * @deprecated Use {@link Builder#setIgnoreSurroundingSpaces(boolean) Builder#setIgnoreSurroundingSpaces(true)}
  2782.      */
  2783.     @Deprecated
  2784.     public CSVFormat withIgnoreSurroundingSpaces() {
  2785.         return builder().setIgnoreSurroundingSpaces(true).get();
  2786.     }

  2787.     /**
  2788.      * Builds a new {@code CSVFormat} with the parser trimming behavior of the format set to the given value.
  2789.      *
  2790.      * @param ignoreSurroundingSpaces the parser trimming behavior, {@code true} to remove the surrounding spaces, {@code false} to leave the spaces as is.
  2791.      * @return A new CSVFormat that is equal to this but with the specified trimming behavior.
  2792.      * @deprecated Use {@link Builder#setIgnoreSurroundingSpaces(boolean)}
  2793.      */
  2794.     @Deprecated
  2795.     public CSVFormat withIgnoreSurroundingSpaces(final boolean ignoreSurroundingSpaces) {
  2796.         return builder().setIgnoreSurroundingSpaces(ignoreSurroundingSpaces).get();
  2797.     }

  2798.     /**
  2799.      * Builds a new {@code CSVFormat} with conversions to and from null for strings on input and output.
  2800.      * <ul>
  2801.      * <li><strong>Reading:</strong> Converts strings equal to the given {@code nullString} to {@code null} when reading records.</li>
  2802.      * <li><strong>Writing:</strong> Writes {@code null} as the given {@code nullString} when writing records.</li>
  2803.      * </ul>
  2804.      *
  2805.      * @param nullString the String to convert to and from {@code null}. No substitution occurs if {@code null}
  2806.      * @return A new CSVFormat that is equal to this but with the specified null conversion string.
  2807.      * @deprecated Use {@link Builder#setNullString(String)}
  2808.      */
  2809.     @Deprecated
  2810.     public CSVFormat withNullString(final String nullString) {
  2811.         return builder().setNullString(nullString).get();
  2812.     }

  2813.     /**
  2814.      * Builds a new {@code CSVFormat} with the quoteChar of the format set to the specified character.
  2815.      *
  2816.      * @param quoteChar the quote character
  2817.      * @return A new CSVFormat that is equal to this but with the specified character as quoteChar
  2818.      * @throws IllegalArgumentException thrown if the specified character is a line break
  2819.      * @deprecated Use {@link Builder#setQuote(char)}
  2820.      */
  2821.     @Deprecated
  2822.     public CSVFormat withQuote(final char quoteChar) {
  2823.         return builder().setQuote(quoteChar).get();
  2824.     }

  2825.     /**
  2826.      * Builds a new {@code CSVFormat} with the quoteChar of the format set to the specified character.
  2827.      *
  2828.      * @param quoteChar the quote character, use {@code null} to disable.
  2829.      * @return A new CSVFormat that is equal to this but with the specified character as quoteChar
  2830.      * @throws IllegalArgumentException thrown if the specified character is a line break
  2831.      * @deprecated Use {@link Builder#setQuote(Character)}
  2832.      */
  2833.     @Deprecated
  2834.     public CSVFormat withQuote(final Character quoteChar) {
  2835.         return builder().setQuote(quoteChar).get();
  2836.     }

  2837.     /**
  2838.      * Builds a new {@code CSVFormat} with the output quote policy of the format set to the specified value.
  2839.      *
  2840.      * @param quoteMode the quote policy to use for output.
  2841.      * @return A new CSVFormat that is equal to this but with the specified quote policy
  2842.      * @deprecated Use {@link Builder#setQuoteMode(QuoteMode)}
  2843.      */
  2844.     @Deprecated
  2845.     public CSVFormat withQuoteMode(final QuoteMode quoteMode) {
  2846.         return builder().setQuoteMode(quoteMode).get();
  2847.     }

  2848.     /**
  2849.      * Builds a new {@code CSVFormat} with the record separator of the format set to the specified character.
  2850.      *
  2851.      * <p>
  2852.      * <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
  2853.      * "\r\n"
  2854.      * </p>
  2855.      *
  2856.      * @param recordSeparator the record separator to use for output.
  2857.      * @return A new CSVFormat that is equal to this but with the specified output record separator
  2858.      * @deprecated Use {@link Builder#setRecordSeparator(char)}
  2859.      */
  2860.     @Deprecated
  2861.     public CSVFormat withRecordSeparator(final char recordSeparator) {
  2862.         return builder().setRecordSeparator(recordSeparator).get();
  2863.     }

  2864.     /**
  2865.      * Builds a new {@code CSVFormat} with the record separator of the format set to the specified String.
  2866.      *
  2867.      * <p>
  2868.      * <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
  2869.      * "\r\n"
  2870.      * </p>
  2871.      *
  2872.      * @param recordSeparator the record separator to use for output.
  2873.      * @return A new CSVFormat that is equal to this but with the specified output record separator
  2874.      * @throws IllegalArgumentException if recordSeparator is none of CR, LF or CRLF
  2875.      * @deprecated Use {@link Builder#setRecordSeparator(String)}
  2876.      */
  2877.     @Deprecated
  2878.     public CSVFormat withRecordSeparator(final String recordSeparator) {
  2879.         return builder().setRecordSeparator(recordSeparator).get();
  2880.     }

  2881.     /**
  2882.      * Builds a new {@code CSVFormat} with skipping the header record set to {@code true}.
  2883.      *
  2884.      * @return A new CSVFormat that is equal to this but with the specified skipHeaderRecord setting.
  2885.      * @see Builder#setSkipHeaderRecord(boolean)
  2886.      * @see Builder#setHeader(String...)
  2887.      * @since 1.1
  2888.      * @deprecated Use {@link Builder#setSkipHeaderRecord(boolean) Builder#setSkipHeaderRecord(true)}
  2889.      */
  2890.     @Deprecated
  2891.     public CSVFormat withSkipHeaderRecord() {
  2892.         return builder().setSkipHeaderRecord(true).get();
  2893.     }

  2894.     /**
  2895.      * Builds a new {@code CSVFormat} with whether to skip the header record.
  2896.      *
  2897.      * @param skipHeaderRecord whether to skip the header record.
  2898.      * @return A new CSVFormat that is equal to this but with the specified skipHeaderRecord setting.
  2899.      * @see Builder#setHeader(String...)
  2900.      * @deprecated Use {@link Builder#setSkipHeaderRecord(boolean)}
  2901.      */
  2902.     @Deprecated
  2903.     public CSVFormat withSkipHeaderRecord(final boolean skipHeaderRecord) {
  2904.         return builder().setSkipHeaderRecord(skipHeaderRecord).get();
  2905.     }

  2906.     /**
  2907.      * 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
  2908.      * and LF on Linux.
  2909.      *
  2910.      * <p>
  2911.      * <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
  2912.      * "\r\n"
  2913.      * </p>
  2914.      *
  2915.      * @return A new CSVFormat that is equal to this but with the operating system's line separator string.
  2916.      * @since 1.6
  2917.      * @deprecated Use {@link Builder#setRecordSeparator(String) setRecordSeparator(System.lineSeparator())}
  2918.      */
  2919.     @Deprecated
  2920.     public CSVFormat withSystemRecordSeparator() {
  2921.         return builder().setRecordSeparator(System.lineSeparator()).get();
  2922.     }

  2923.     /**
  2924.      * Builds a new {@code CSVFormat} to add a trailing delimiter.
  2925.      *
  2926.      * @return A new CSVFormat that is equal to this but with the trailing delimiter setting.
  2927.      * @since 1.3
  2928.      * @deprecated Use {@link Builder#setTrailingDelimiter(boolean) Builder#setTrailingDelimiter(true)}
  2929.      */
  2930.     @Deprecated
  2931.     public CSVFormat withTrailingDelimiter() {
  2932.         return builder().setTrailingDelimiter(true).get();
  2933.     }

  2934.     /**
  2935.      * Builds a new {@code CSVFormat} with whether to add a trailing delimiter.
  2936.      *
  2937.      * @param trailingDelimiter whether to add a trailing delimiter.
  2938.      * @return A new CSVFormat that is equal to this but with the specified trailing delimiter setting.
  2939.      * @since 1.3
  2940.      * @deprecated Use {@link Builder#setTrailingDelimiter(boolean)}
  2941.      */
  2942.     @Deprecated
  2943.     public CSVFormat withTrailingDelimiter(final boolean trailingDelimiter) {
  2944.         return builder().setTrailingDelimiter(trailingDelimiter).get();
  2945.     }

  2946.     /**
  2947.      * Builds a new {@code CSVFormat} to trim leading and trailing blanks. See {@link #getTrim()} for details of where this is used.
  2948.      *
  2949.      * @return A new CSVFormat that is equal to this but with the trim setting on.
  2950.      * @since 1.3
  2951.      * @deprecated Use {@link Builder#setTrim(boolean) Builder#setTrim(true)}
  2952.      */
  2953.     @Deprecated
  2954.     public CSVFormat withTrim() {
  2955.         return builder().setTrim(true).get();
  2956.     }

  2957.     /**
  2958.      * Builds a new {@code CSVFormat} with whether to trim leading and trailing blanks. See {@link #getTrim()} for details of where this is used.
  2959.      *
  2960.      * @param trim whether to trim leading and trailing blanks.
  2961.      * @return A new CSVFormat that is equal to this but with the specified trim setting.
  2962.      * @since 1.3
  2963.      * @deprecated Use {@link Builder#setTrim(boolean)}
  2964.      */
  2965.     @Deprecated
  2966.     public CSVFormat withTrim(final boolean trim) {
  2967.         return builder().setTrim(trim).get();
  2968.     }

  2969. }