Search code examples
javacsvsupercsv

SuperCSV reading from multiple files and parsing into one bean object


I am currently trying to read in multiple CSV files using beanReader before taking a few columns from each and parsing them into one bean.

So far I cannot seem to parse columns from different files into one bean object. Is this even possible with ICsvBeanReader?


Solution

  • Yes, it's possible :) As of Super CSV 2.2.0 you can read into an existing bean (see javadoc).

    The following example uses 3 readers simultaneously (operating on 3 different files) - the first reader is used to create the bean, the other 2 just update the existing bean. This approach assumes that each file has the same number of rows (and that each row number represents the same person). If they don't, but they share some unique identifier, you'll have to read all the records from the first file into memory first, then update from the second/third matching on the identifier.

    I've tried to make it a little bit smart, so you don't have to hard-code the name mapping - it just nulls out the headers it doesn't know about (so that Super CSV doesn't attempt to map fields that don't exist in your bean - see the partial reading examples on the website). Of course this will only work if your file has headers - otherwise you'll just have to hard code the mapping arrays with nulls in the appropriate places.

    Person bean

    public class Person {
        private String firstName;
        private String sex;
        private String country;
        // getters/setters
    }
    

    Example code

    public class Example {
    
        private static final String FILE1 = "firstName,lastName\nJohn,Smith\nSally,Jones";
        private static final String FILE2 = "age,sex\n21,male\n24,female";
        private static final String FILE3 = "city,country\nBrisbane,Australia\nBerlin,Germany";
        private static final List<String> DESIRED_HEADERS = Arrays.asList("firstName", "sex", "country");
    
        @Test
        public void testMultipleFiles() throws Exception {
    
            try (
                ICsvBeanReader reader1 = new CsvBeanReader(new StringReader(FILE1), CsvPreference.STANDARD_PREFERENCE);
                ICsvBeanReader reader2 = new CsvBeanReader(new StringReader(FILE2), CsvPreference.STANDARD_PREFERENCE);
                ICsvBeanReader reader3 = new CsvBeanReader(new StringReader(FILE3), CsvPreference.STANDARD_PREFERENCE);){
    
                String[] mapping1 = getNameMappingFromHeader(reader1);
                String[] mapping2 = getNameMappingFromHeader(reader2);
                String[] mapping3 = getNameMappingFromHeader(reader3);
    
                Person person;
                while((person = reader1.read(Person.class, mapping1)) != null){
                    reader2.read(person, mapping2);
                    reader3.read(person, mapping3);
                    System.out.println(person);
                }
            } 
    
        }
    
        private String[] getNameMappingFromHeader(ICsvBeanReader reader) throws IOException{
            String[] header = reader.getHeader(true);
    
            // only read in the desired fields (set unknown headers to null to ignore)
            for (int i = 0; i < header.length; i++){
                if (!DESIRED_HEADERS.contains(header[i])){
                    header[i] = null;
                }
            }
    
            return header;
        }
    }
    

    Output

    Person [firstName=John, sex=male, country=Australia]
    Person [firstName=Sally, sex=female, country=Germany]