如何从opencsv中的特定标题中读取?

时间:2015-07-14 18:08:05

标签: java opencsv

我有一个csv文件。我想从中提取特定的列。例如: 说,我有csv:

id1,caste1,salary,name1
63,Graham,101153.06,Abraham
103,Joseph,122451.02,Charlie
63,Webster,127965.91,Violet
76,Smith,156150.62,Eric
97,Moreno,55867.74,Mia
65,Reynolds,106918.14,Richard

如何使用opencsv只读取头文件caste1中的数据?

5 个答案:

答案 0 :(得分:7)

Magnilex和Sparky是正确的,因为CSVReader不支持按列名读取值。但话说有两种方法可以做到这一点。

鉴于您拥有列名并且默认CSVReader读取标题,您可以在第一个标题中搜索该位置,然后从那里开始使用该标题;

private int getHeaderLocation(String[] headers, String columnName) {
   return Arrays.asList(headers).indexOf(columnName);
}

所以你的方法看起来像(省去了你需要输入的大量错误检查)

CSVReader reader = new CSVReader(new FileReader("yourfile.csv"));
String [] nextLine;
int columnPosition;

nextLine = reader.readNext();
columnPosition = getHeaderLocation(nextLine, "castle1");

while ((nextLine = reader.readNext()) != null && columnPosition > -1) {
   // nextLine[] is an array of values from the line
   System.out.println(nextLine[columnPosition]);
}

如果时间紧迫,我只会做上述事情而且你只关心一栏。这是因为openCSV可以使用CsvToBean类和HeaderColumnNameMappingStrategy直接转换为具有与标题列名称相同的变量的对象。

首先,你要定义一个具有字段的类(实际上你只需要放入你想要的字段 - 额外的内容被忽略,缺少的是null或默认值)。

public class CastleDTO {
   private int id1;
   private String castle1;
   private double salary;
   private String name1;

   // have all the getters and setters here....
}

然后你的代码看起来像

CSVReader reader = new CSVReader(new FileReader("yourfile.csv"));
HeaderColumnNameMappingStrategy<CastleDTO> castleStrategy = new HeaderColumnNameMappingStrategy<CastleDTO>();
CsvToBean<CastleDTO> csvToBean = new CsvToBean<CastleDTO>();

List<CastleDTO> castleList = csvToBean.parse(castleStrategy, reader);

for (CastleDTO dto : castleList) {
   System.out.println(dto.getCastle1());
}

答案 1 :(得分:2)

opencsv中没有内置功能可以按名称从列中读取。

official FAQ example有关于如何从文件中读取的以下示例:

CSVReader reader = new CSVReader(new FileReader("yourfile.csv"));
String [] nextLine;
while ((nextLine = reader.readNext()) != null) {
   // nextLine[] is an array of values from the line
   System.out.println(nextLine[0] + nextLine[1] + "etc...");
}

您只需通过使用nextLine[1]访问行来获取每行第二列中的值(请记住,数组索引基于零)。

因此,在您的情况下,您只需阅读第二行:

CSVReader reader = new CSVReader(new FileReader("yourfile.csv"));
String [] nextLine;
while ((nextLine = reader.readNext()) != null) {
   System.out.println(nextLine[1]);
}

有关从标题中确定列索引的更复杂方法,请参阅the answer from Scott Conway

答案 2 :(得分:1)

来自opencsv docs

从4.2版开始,还有另一种便捷的方式来读取CSV文件,甚至不需要创建特殊的类。如果您的CSV文件具有标题,则只需初始化CSVReaderHeaderAware并开始将值作为地图读出即可:

  reader = new CSVReaderHeaderAware(new FileReader("yourfile.csv"));
  record = reader.readMap();

.readMap()将返回一条记录。您需要反复调用.readMap()来获取所有记录,直到null到达结尾(或第一个空行)为止,例如:

Map<String, String> values;

while ((values = reader.readMap()) != null) {

    // consume the values here

}

该类还具有另一个允许更多自定义的构造函数,例如:

CSVReaderHeaderAware reader = new CSVReaderHeaderAware(
        new InputStreamReader(inputStream),
        0,      // skipLines
        parser, // custom parser
        false,  // keep end of lines
        true,   // verify reader
        0,      // multiline limit
        null    // null for default locale
);

我发现一个缺点是,由于读者很懒,它没有提供记录数,因此,如果您需要知道总数(例如显示正确的进度信息),则需要使用另一个阅读器只是为了数行。

您还可以使用CSVReaderHeaderAwareBuilder

答案 3 :(得分:0)

我有一个任务要从现有的csv中删除几列,例如csv:

FirstName, LastName, City, County, Zip
Steve,Hopkins,London,Greater London,15554
James,Bond,Vilnius,Vilniaus,03250

我只需要带有值的FirstName和LastName列,并且顺序必须相同非常重要-默认rd.readMap()不会保留顺序,此任务的代码如下:

        String[] COLUMN_NAMES_TO_REMOVE = new String[]{"", "City", "County", "Zip"};
        CSVReaderHeaderAware rd = new CSVReaderHeaderAware(new StringReader(old.csv));
        CSVWriter writer = new CSVWriter((new FileWriter(new.csv)),
                CSVWriter.DEFAULT_SEPARATOR, CSVWriter.NO_QUOTE_CHARACTER, CSVWriter.NO_ESCAPE_CHARACTER, CSVWriter.DEFAULT_LINE_END);

        // let's get private field
        Field privateField = CSVReaderHeaderAware.class.getDeclaredField("headerIndex");
        privateField.setAccessible(true);
        Map<String, Integer> headerIndex = (Map<String, Integer>) privateField.get(rd);

        // do ordering in natural order - 0, 1, 2 ... n
        Map<String, Integer> sortedInNaturalOrder = headerIndex.entrySet().stream()
                .sorted(Map.Entry.comparingByValue(Comparator.naturalOrder()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                        (oldValue, newValue) -> oldValue, LinkedHashMap::new));

        // let's get headers in natural order
        List<String> headers = sortedInNaturalOrder.keySet().stream().distinct().collect(Collectors.toList());

        // let's remove headers
        List<String> removedColumns = new ArrayList<String>(Arrays.asList(COLUMN_NAMES_TO_REMOVE));
        headers.removeAll(removedColumns);
        // save column names           
        writer.writeNext(headers.toArray(new String[headers.size()]));
   
        List<String> keys = new ArrayList<>();
        Map<String, String> values;
        while ((values = rd.readMap()) != null) {
            for (String key : headers) {
                keys.add(values.get(key));
                if (keys.size() == headers.size()) {
                    String[] itemsArray = new String[headers.size()];
                    itemsArray = keys.toArray(itemsArray);
                    // save values                       
                    writer.writeNext(itemsArray);
                    keys.clear();
                }
            }
        }
        writer.flush();

输出:

FirstName, LastName
Steve,Hopkins
James,Bond

答案 4 :(得分:-2)

查看javadoc

如果您创建CSVReader对象,则可以使用方法.readAll来拉取整个文件。它返回一个String []列表,每个String []代表一行文件。所以现在你有每行的标记,你只需要第二个元素,所以将它们分开,因为它们已经很好地用分隔符给你了。在每一行上你只需要第二个元素,所以:

public static void main(String[] args){
    String data = "63,Graham,101153.06,Abraham";
    String result[] = data.split(",");
    System.out.print(result[1]);
}