如何动态选择OpenCSV应用程序使用的分隔符?



我有一个代码,读取CSV文件并使用CsvToBean将内容转换为Java对象。

public static <T> List<T> parseInputStreamFromCsv(InputStream inputStream, Class<T> clazz) {
  try (Reader reader = new BufferedReader(new InputStreamReader(inputStream))) {
    CsvToBean<T> csvToBean = new CsvToBeanBuilder<T>(reader)
        .withType(clazz)
        .withIgnoreLeadingWhiteSpace(true)
        .build();
    return csvToBean.parse();
  } catch (Exception ex) {
    throw new ConversionFailedException("Error converting CSV");
  }
}

有时用户上传CSV文件时使用逗号作为分隔符,然后其他用户上传CSV文件时使用分号作为分隔符。

我的问题是存在一种在我的CsvToBeanBuilder中动态设置分隔符的方法,创建一种转换两个文件(使用逗号和分号)的方法,而不会出现任何问题。谢谢!

我的问题是存在一种在我的CsvToBeanBuilder中动态设置分隔符的方法,创建一种转换两个文件(使用逗号和分号)的方法,而没有任何问题。

以下方法将同时处理分隔符;,:

使用动态分隔符检测解析

注意:
根据OP的要求,下面的方法支持两个主要字符分隔行条目

public static <T> List<T> parseFromCsvWithSeparatorDetection(
                          InputStream inputStream, Class<T> type, String[] columns)
                          throws IOException, CsvException {
    final StringBuilder textBuilder = new StringBuilder();
    try (Reader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
      int c;
      while ((c = reader.read()) != -1) {
        textBuilder.append((char) c);
      }
    }
    final String csvContent = textBuilder.toString();
    final char detectedSeparator;
    if(csvContent.contains(";")) {
      detectedSeparator = ';'; // semicolon case
    } else {
      detectedSeparator = ','; // default case
    }
    try (Reader reader = new StringReader(csvContent)) {
      ColumnPositionMappingStrategy<T> strategy = new ColumnPositionMappingStrategy<>();
      strategy.setColumnMapping(columns);
      strategy.setType(type);
      CsvToBean<T> csvToBean = new CsvToBeanBuilder<T>(reader)
              .withMappingStrategy(strategy)
              .withSeparator(detectedSeparator)
              .withIgnoreLeadingWhiteSpace(true)
              .build();
      return csvToBean.parse();
    } 
  }

用法示例
String[] columns = new String[]{"a", "b"};
InputStream in = ... // <-- set/obtain InputStream here
try {
    List<Bean> objects = CSVUtils.parseFromCsvWithSeparatorDetection(in, Bean.class, columns);
} catch (IOException | CsvException e) {
    e.printStackTrace();
}

给定类Bean有两个String属性ab,一个无参数的构造函数(和getter/setter方法)

演示csv数据

A1;B1
A2;B2

A1,B1
A2,B2

我用17和OpenCSV 5.7.1测试了上面的内容,也应该适用于更老的或最近的5。x版本。

洞穴!

上面的方法应该只能如果用于处理的内存在运行时不是问题,则使用。原因:inputStream被完全消耗并读取到内存中——然而,只有一次。然而,在低资源环境下使用非常大的(而且很可能是巨大的)csv文件(可能有数百万行)时,这可能会有问题。

最新更新