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