如何轻松处理CSV文件到List <MyClass>

5 java csv parsing filereader

在我的应用程序中,我使用了很多CSV文件,我必须阅读它们并根据它们构建列表.我想发现一个简单的方法来做到这一点.你知道任何简单的框架,它没有使用配置文件的数量等吗?

例如,我有一个人类:

public class Person {
    String name;
    String surname;

    double shoeSize;
    boolean sex; // true: male, false:female

    public Person() {
    }

    public String getName() {
            return name;
    }

    public void setName(String name) {
            this.name = name;
    }

    public String getSurname() {
            return surname;
    }

    public void setSurname(String surname) {
            this.surname = surname;
    }

    public double getShoeSize() {
            return shoeSize;
    }

    public void setShoeSize(double shoeSize) {
            this.shoeSize = shoeSize;
    }

    public boolean isSe) {
            return sex;
    }

    public void setSeboolean sex) {
            this.sex = sex;
    }
Run Code Online (Sandbox Code Playgroud)

}

对于本课程,我准备了CSV文件:

name,surname,shoesize,sex
Tom,Tommy,32,true
Anna,Anny,27,false
Run Code Online (Sandbox Code Playgroud)

我怎么能轻易做到?

Asa*_*saf 11

读取和序列化数据的最简单方法之一是使用 Jackson 库。它还有一个 CSV 扩展,你可以在这里找到 wiki

假设你有一个这样的 Pojo:

@JsonPropertyOrder({ "name", "surname", "shoesize", "gender" })
public class Person {

    public String name;
    public String surname;
    public int shoesize;
    public String gender;

}
Run Code Online (Sandbox Code Playgroud)

和这样的 CSV:

Tom,Tommy,32,m
Anna,Anny,27,f
Run Code Online (Sandbox Code Playgroud)

然后阅读它是这样完成的:

MappingIterator<Person> personIter = new CsvMapper().readerWithTypedSchemaFor(Person.class).readValues(csvFile);
List<Person> people = personIter.readAll();
Run Code Online (Sandbox Code Playgroud)

This is simple enough for my taste, basically all you need to do is add the column order in your CSV file using the @JsonPropertyOrder annotation and then just read the file using the above 2 lines.


Shi*_*mar 7

有很多用 Java 编写的优秀框架可以解析 CSV 文件并形成对象列表。OpenCSVJSefajCSV仅举几例。

对于您的要求,我相信jCSV最适合。下面是 jCSV 中的示例代码,您可以轻松使用它们。

Reader reader = new FileReader("persons.csv");

CSVReader<Person> csvPersonReader = ...;

// read all entries at once
List<Person> persons = csvPersonReader.readAll();

// read each entry individually
Iterator<Person> it = csvPersonReader.iterator();
while (it.hasNext()) {
  Person p = it.next();
  // ...
}
Run Code Online (Sandbox Code Playgroud)

而且,解析一个CSV文件并把它转换成一个List也没什么大不了的,不用任何框架就可以实现,如下图。

br = new BufferedReader(new FileReader(csvFileToRead));  
List<Person> personList = new ArrayList<>();
while ((line = br.readLine()) != null) {  
       // split on comma(',')  
       String[] personCsv = line.split(splitBy);  

       // create car object to store values  
       Person personObj = new Person();  

       // add values from csv to car object  
       personObj.setName(personCsv[0]);  
       personObj.setSurname(personCsv[1]);  
       personObj.setShoeSize(personCsv[2]);  
       personObj.setGender(personCsv[3]); 

       // adding car objects to a list  
       personList.add(personObj);         
} 
Run Code Online (Sandbox Code Playgroud)

如果 CSV 列到 bean 对象的映射在实际情况下很复杂、重复或很大,那么可以使用DozerBeanMapper轻松完成。

希望这会帮助你。

石狮


Mar*_* A. 5

不确定您是否需要使用外部库(并采取通常隐含的性能损失)。实现起来是一件非常简单的事情。如果不出意外,了解这样一个库中幕后发生的事情总是有帮助的:

public List<Person> readFile(String fileName) throws IOException {
    List<Person> result = new ArrayList<Person>();
    BufferedReader br = new BufferedReader(new FileReader(new File(fileName)));
    try {
        // Read first line
        String line = br.readLine();
        // Make sure file has correct headers
        if (line==null) throw new IllegalArgumentException("File is empty");
        if (!line.equals("name,surname,shoesize,sex"))
            throw new IllegalArgumentException("File has wrong columns: "+line);
        // Run through following lines
        while ((line = br.readLine()) != null) {
            // Break line into entries using comma
            String[] items = line.split(",");
            try {
                // If there are too many entries, throw a dummy exception, if
                // there are too few, the same exception will be thrown later
                if (items.length>4) throw new ArrayIndexOutOfBoundsException(); 
                // Convert data to person record
                Person person = new Person();
                person.setName    (                     items[0] );
                person.setSurname (                     items[1] );
                person.setShoeSize(Double .parseDouble (items[2]));
                person.setSex     (Boolean.parseBoolean(items[3]));
                result.add(person);
            } catch (ArrayIndexOutOfBoundsException|NumberFormatException|NullPointerException e) {
                // Caught errors indicate a problem with data format -> Print warning and continue
                System.out.println("Invalid line: "+ line);
            }
        }
        return result;
    } finally {
        br.close();
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,catch语句使用 Java 7 multi-catch。对于较旧的 Java 版本,请将其拆分为 3 个 catch 块或替换ArrayIndexOutOfBoundsException|NumberFormatException|NullPointerExceptionException. 后者通常是不鼓励的,因为它也掩盖并忽略了所有其他异常,但在像这样的简单示例中,风险可能不太高。

不幸的是,这个答案特定于您的问题,但鉴于它非常简单,它也应该很容易适应其他情况......

您可以做的另一件事是line在 while 循环内使用正则表达式进行匹配,而不是简单地根据逗号将其拆分。这样,您还可以一次性实现数据验证(例如,只匹配鞋号的合理数字)。

请注意,如果您的姓名包含逗号,然后用引号括起来(例如“Jackson, Jr.”作为姓氏),则上述实现将不起作用。如果您使用如上所述的正则表达式,或者通过检查姓氏的第一个字母并且如果它是引号,则可以“轻松”地涵盖这种情况,将 item[1] 与 item[2] 组合并使用 item[3] ] 和 item[4] 代替鞋码和性别。此处建议的大多数外部库可能会涵盖这种特殊情况,因此,如果您不担心任何依赖项、许可问题和性能问题,那么这些可能是更简单的出路...


Leo*_*Leo -1

我认为 SuperCSV + Dozer 易于使用,并且对于 java bean CSV 序列化非常强大

http://supercsv.sourceforge.net/dozer.html