Parsing CSV file with BufferedReader vs Scanner I have to parse a file line-by-line and in single line I have split by ",". The first string is the name and the second is the count.

Finally, I have to display the Key and Count, for example:




Peter,2
Smith,3
Peter,3
Smith,5



I should display as Peter 5 and Smith 8.

I confused about choosing between BufferedReader vs Scanner.  I went through this link and came up with these two approaches. I would like to get your reviews.




BufferedReader

private HashMap&lt;String, MutableLong&gt; readFile(File file) throws IOException {
    final HashMap&lt;String, MutableLong&gt; keyHolder = new HashMap&lt;&gt;();
    try (BufferedReader br = new BufferedReader(new InputStreamReader(
            new FileInputStream(file), "UTF-8"))) {
        for (String line; (line = br.readLine()) != null;) {
            // processing the line.
            final String[] keyContents = line
                    .split(KeyCountExam.COMMA_DELIMETER);
            if (keyContents.length == 2) {
                final String keyName = keyContents[0];
                final long count = Long.parseLong(keyContents[1]);
                final MutableLong keyCount = keyHolder.get(keyName);
                if (keyCount != null) {
                    keyCount.add(count);
                    keyHolder.put(keyName, keyCount);
                } else {
                    keyHolder.put(keyName, new MutableLong(count));
                }
            }

        }
    }
    return keyHolder;
}

private static final String COMMA_DELIMETER = ",";
private static volatile Pattern commaPattern = Pattern.compile(COMMA_DELIMETER);


I have used MutableLong, since I don't want to create a BigInteger each time. Again, it may be a very big file and I don't have control on how max a key can occur.
Scanner and two delimiters

private static final String LINE_SEPARATOR_PATTERN = "\r\n|[\n\r\u2028\u2029\u0085]";
private static final String LINE_PATTERN = ".*(" + LINE_SEPARATOR_PATTERN
        + ")|.+$";
private static volatile Pattern linePattern = Pattern.compile(LINE_PATTERN);



I have went through the hasNext in Scanner, and to me, there is no harm in switching the Pattern. And I believe from Java 7, Scanner does have a limited buffer and can be enough for this kind of file.

Does anyone prefer Approach 2 over Approach 1, or do we have any other option than this?  I just did sop for testing purpose. Obviously the same code in approach 1 would replace here. Using split in Approach 1 would create multiple String instances, which can be avoided here, by scanning a char sequence.

private HashMap&lt;String, BigInteger&gt; readFileScanner(File file)
            throws IOException {
        final HashMap&lt;String, BigInteger&gt; keyHolder = new HashMap&lt;&gt;();
        try (Scanner br = new Scanner(file, "UTF-8")) {
            while (br.hasNext()) {
                br.useDelimiter(commaPattern);
                System.out.println(br.next());
                System.out.println(br.next());
                br.useDelimiter(linePattern);
            }
        }
        return keyHolder;
    }
I think that splitting a string on commas is the worse approach for serious CSV parsing.

There is no single standard csv format, but RFC 4180 comes close to being a de facto standard.  As described in Section 2, CSV fields may be double-quoted (and if so, a literal " would be represented as a pair of " characters).  Simply splitting a line on commas does not give you the ability to ever implement support for interpreting quoting.

With a Scanner, you can use tools such as useDelimiter(Pattern) and findInLine(Pattern) to simultaneously look for " and , characters, giving you a chance to write a real parser based on the ABNF grammar in RFC 4180.

Of course, unless are deliberately reinventing-the-wheel, you should just use an existing library, such as Apache Commons CSV or opencsv.