/// <summary> /// Parses the specified reader as a CSV file where the separator is specified and might not be a comma. /// <para> /// This factory method takes a <seealso cref="Reader"/>. /// Callers are encouraged to use <seealso cref="CharSource"/> instead of {@code Reader} /// as it allows the resource to be safely managed. /// </para> /// <para> /// This factory method allows the separator to be controlled. /// For example, a tab-separated file is very similar to a CSV file, the only difference is the separator. /// </para> /// <para> /// CSV files sometimes contain a Unicode Byte Order Mark. /// Callers are responsible for handling this, such as by using <seealso cref="UnicodeBom"/>. /// /// </para> /// </summary> /// <param name="reader"> the file resource </param> /// <param name="headerRow"> whether the source has a header row, an empty source must still contain the header </param> /// <param name="separator"> the separator used to separate each field, typically a comma, but a tab is sometimes used </param> /// <returns> the CSV file </returns> /// <exception cref="UncheckedIOException"> if an IO exception occurs </exception> /// <exception cref="IllegalArgumentException"> if the file cannot be parsed </exception> public static CsvFile of(Reader reader, bool headerRow, char separator) { ArgChecker.notNull(reader, "source"); IList <string> lines = Unchecked.wrap(() => CharStreams.readLines(reader)); return(create(lines, headerRow, separator)); }