Java function to read a CSV file

  • I have a java function that reads a csv and returns its content as a Vector<Vector<String>>.



    The function seems to work as I need it, but my gut feeling says it could be better (never mind the fact that it is declared throws Exception).



    So here it is:



    private static Vector<Vector<String>> readTXTFile(String csvFileName) throws Exception {

    BufferedReader stream = new BufferedReader(
    new InputStreamReader(
    new FileInputStream(csvFileName)));

    Vector<Vector<String>> csvData = new Vector<Vector<String>>();

    String line;
    while ((line = stream.readLine()) != null) {

    csvData.add(new Vector<String>() );

    String[] values = line.split(",");

    for (int v=0; v<values.length; v++) {
    csvData.get(csvData.size()-1).add(values[v]);
    }
    }

    return csvData;
    }


    Background



    Ultimately, the CSV Data will be used to fill a JTable. I could have used an String[][] for the data too, but it seemed that constructing a dynamic String[][] from a csv file would have been even more combersome (although I stand ready to be corrected on this, too).


    Something like Óscar López said, don't use concrete class for method return.And Vector will cause performance hit.

  • The code can be simplified and improved in several ways, and the inner loop can be made tighter. Let me show you how:



    private static List<List<String>> readTXTFile(String csvFileName) throws IOException {

    String line = null;
    BufferedReader stream = null;
    List<List<String>> csvData = new ArrayList<List<String>>();

    try {
    stream = new BufferedReader(new FileReader(csvFileName));
    while ((line = stream.readLine()) != null) {
    String[] splitted = line.split(",");
    List<String> dataLine = new ArrayList<String>(splitted.length);
    for (String data : splitted)
    dataLine.add(data);
    csvData.add(dataLine);
    }
    } finally {
    if (stream != null)
    stream.close();
    }

    return csvData;

    }



    • A method should throw an exception as specific as possible, here it's better to use IOException instead of simply Exception

    • Whenever possible, return interface types instead of concrete classes. Using List is preferred to using Vector, this allows you the flexibility to change the implementation of the collection later

    • Talking about collections: Vector is thread-safe and synchronized in many of its public methods, that can cause a performance hit. If you don't need that, it's better to use ArrayList, it's a drop-in replacement and won't incur in the performance penalty of synchronization.

    • There's a simpler way to instantiate a BufferedReader, using a FileReader instead of using an InputStreamReader plus a FileInputStream. Besides, FileReader will take care of pesky details regarding character encoding

    • There's a simpler way to add elements to the last List added to csvData, as shown in the code

    • There's a simpler way to iterate through the String[] returned by split(), using an enhanced loop

    • Don't forget to close your streams! preferably inside a finally block



    If you don't need to add more elements to the returned List<List<String>>, you can use the following alternate version. It's faster because it avoids copying the String[] of split elements, but it won't allow adding new elements, as per the contract of asList():



    private static List<List<String>> readTXTFile(String csvFileName) throws IOException {

    String line = null;
    BufferedReader stream = null;
    List<List<String>> csvData = new ArrayList<List<String>>();

    try {
    stream = new BufferedReader(new FileReader(csvFileName));
    while ((line = stream.readLine()) != null)
    csvData.add(Arrays.asList(line.split(",")));
    } finally {
    if (stream != null)
    stream.close();
    }

    return csvData;

    }

License under CC-BY-SA with attribution


Content dated before 7/24/2021 11:53 AM