как получить и проверить заголовок csv в открытом csv?

Я хочу получить заголовок из файла csv. Если я не использую этот skipLines, я получу заголовок в массиве индексов 0. Но я хочу получить заголовок напрямую, используя HeaderColumnNameMappingStrategy, но это не будет работать с моим кодом.

Я также хочу проверить список столбцов заголовка (например, csv не может содержать дополнительный столбец)

Я также проверил это Как проверить заголовки csv с помощью opencsv но мне это не помогло.

@SuppressWarnings({ "unchecked", "rawtypes" })
public Map<String, Object> handleStockFileUpload(MultipartFile file, Long customerId) {
    Map<String, Object> responseMap = new HashMap<>();
    responseMap.put("datamap", "");
    responseMap.put("errormap", "");
    responseMap.put("errorkeys", "");

    List<Map<String, Integer>> list = new ArrayList<>();
    List<StockCsvDTO> csvStockList = new ArrayList<>();

    try {
        String fileName = new SimpleDateFormat("yyyy_MM_dd_HHmmss").format(new Date()) + "_" + file.getOriginalFilename();
        responseMap.put("filename", fileName);

        File stockFile = new File(productsUploadFilePath + fileName);
        stockFile.getParentFile().mkdirs();
        FileOutputStream fos = new FileOutputStream(stockFile);
        fos.write(file.getBytes());
        fos.close();


        CsvTransfer csvTransfer = new CsvTransfer();


        ColumnPositionMappingStrategy ms = new ColumnPositionMappingStrategy();
        ms.setType(StockCsv.class);

        Reader reader = Files.newBufferedReader(Paths.get(productsUploadFilePath + fileName));
        CSVReader csvReader =  new CSVReader(reader);

        CsvToBean cb = new CsvToBeanBuilder(reader)
          .withType(StockCsv.class)
          .withMappingStrategy(ms)
          .withSkipLines(1)
          .build();

       csvTransfer.setCsvList(cb.parse());
       reader.close();


       csvStockList = csvTransfer.getCsvList();

    } catch (Exception e) {
        e.printStackTrace();
        responseMap.put("status", "servererror");
    }

     responseMap.put("datamap", csvStockList);

    return responseMap;
}

person Zenny    schedule 09.05.2019    source источник
comment
вы должны использовать Open Csv или любой другой способ проверки заголовков будет хорошо   -  person Thomas Mwania    schedule 09.05.2019


Ответы (4)


Я нашел следующее решение:

  1. Используйте @CsvBindByName с HeaderColumnNameMappingStrategy, например. аннотируйте свойства вашего компонента с помощью @CsvBindByName:
    public static class HollywoodActor {
        private int id;
        @CsvBindByName(column = "First Name")
        private String firstName;
        @CsvBindByName(column = "Last Name")
        private String lastName;
    // getter / setter
    }
  1. Добавьте такой метод:
    public class CsvParser {

        public <T> ParseResult<T> parseByPropertyNames(Reader csvReader, Class<T> beanClass) throws IOException {
            CSVReader reader = new CSVReaderBuilder(csvReader).withCSVParser(new 
 CSVParserBuilder().build()).build();
            CsvToBean<T> bean = new CsvToBean();
            HeaderColumnNameMappingStrategy<T> mappingStrategy = new HeaderColumnNameMappingStrategy();
            mappingStrategy.setType(beanClass);
            bean.setMappingStrategy(mappingStrategy);
            bean.setCsvReader(reader);
            List<T> beans = bean.parse();
            return new CsvParseResult<>(mappingStrategy.generateHeader(), beans);
        }

а также не забудьте добавить публичный класс ParseResult

    public class ParseResult <T> {
      private final String[] headers;
      private final List<T> lines;
      // all-args constructor & getters
    }
  1. Используйте, а затем используйте их в своем коде:
    String csv = "Id,First Name,Last Name\n" + "1, \"Johnny\", \"Depp\"\n" + "2, \"Al\", \"Pacino\"";
    CsvParseResult<HollywoodActor> parseResult = parser
                .parseByPropertyNames(new InputStreamReader(new ByteArrayInputStream(csv.getBytes(StandardCharsets.UTF_8), HollywoodActor.class)));
  1. Из ParseResult.headers вы можете получить фактические заголовки, которые были в вашем файле .csv. Просто сравните их с тем, что ожидается.

Надеюсь, это поможет!

person Maksim Karatkou    schedule 28.11.2019

Здесь я сравнивал свой csvHeader с originalHeader:

List<String> originalHeader = fileUploadUtility.getHeader(new StockCsv());

List<String> invalidHeader = csvHeader.stream().filter(o -> (originalHeader.stream().filter(f -> f.equalsIgnoreCase(o)).count()) < 1).collect(Collectors.toList());
            if(null != invalidHeader && invalidHeader.size() > 0 && invalidHeader.toString().replaceAll("\\[\\]", "").length() > 0) {
                msg = "Invalid column(s) : " + invalidHeader.toString().replace(", ]", "]") + ". Please remove invalid column(s) from file.";
                resultMap.put(1, msg);
            }


 public List<String> getHeader(T pojo) {
    // TODO Auto-generated method stub
    final CustomMappingStrategy<T> mappingStrategy = new CustomMappingStrategy<>();
    mappingStrategy.setType((Class<? extends T>) pojo.getClass());
    String header[] = mappingStrategy.generateHeader();
    List<String> strHeader = Arrays.asList(header);
    return strHeader;
  }
person Zenny    schedule 20.05.2019

Вот альтернатива вашей нынешней проблеме. Во-первых, определите, как вы ожидаете, что ваши заголовки будут выглядеть. Например:

public static final ArrayList<String> fileFormat = new ArrayList<> (Arrays.asList("Values1", "Values2", "Values3", "Values4")); Теперь напишите метод для возврата пользовательских ошибок, если они существуют:

public String validateCsvFileDetails(MultipartFile file, Set<String> requiredHeadersArray) {
    Set<String> errors = new HashSet<>();
    try {
        InputStream stream = file.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
        String headerLine = reader.readLine();
        if (Objects.isNull(headerLine))
            return "The file has no headers, please ensure it has the correct upload format";
        List<String> headersInFileList;
        String[] headersInFileArray;
        if (headerLine.contains(",")) {
            headersInFileArray = StringUtils.split(headerLine, ",");
            headersInFileList = Arrays.asList(headersInFileArray);
        } else//the headerline has only one headerfield
        {
            headersInFileList = Collections.singletonList(headerLine);
        }
        for (String header : requiredHeadersArray) {
            if (!headersInFileList.contains(header))
                errors.add("The file has the wrong header format, please ensure " + header + " header is present");
        }
        //if there are errors, return it
        if (!errors.isEmpty())
            return sysUtils.getStringFromSet(errors);
        //Ensure the csv file actually has values after the header, but don't read beyond the first line
        String line;
        int counter = 0;

        while ((line = reader.readLine()) != null) {
            counter++;
            if (counter > 0)
                break;
        }
        //if line is null return validation error
        if (Objects.isNull(line))
            return "Cannot upload empty file";
    } catch (Exception e) {
        logger.error(new Object() {
        }.getClass().getEnclosingMethod().getName(), e);
        return "System Error";
    }

    return null;

}

Теперь вы можете проверить заголовки файлов следующим образом:

  String errors = validateCsvFileDetails(file, new HashSet<>(fileFormat));
     if (errors != null)
        return error
    //proceed
person Thomas Mwania    schedule 09.05.2019

Попробуйте это, используя CaptureHeader в качестве предварительного фильтра: ...

private class CustomHeaderColumnNameMappingStrategy<T> extends HeaderColumnNameMappingStrategy {
    private String[] expectedHeadersOrdered = {"Column1", "Column2", "Column3", "Column4", "Column5"};
    @Override
    public void captureHeader(CSVReader reader) throws IOException, CsvRequiredFieldEmptyException {
        String[] actualCsvHeaders = reader.peek();
        String actualHeader, expectedHeader;
        if (expectedHeadersOrdered.length > actualCsvHeaders.length) {
            throw new CsvRequiredFieldEmptyException("Missing header column.");
        } else if (expectedHeadersOrdered.length < actualCsvHeaders.length) {
            throw new IOException("Unexpected extra header column.");
        }
        // Enforce strict column ordering with index
        // TODO: you might want to employ simple hashMap, List, set, etc. as needed
        for (int i=0; i<actualCsvHeaders.length; i++) {
            actualHeader = actualCsvHeaders[i];
            expectedHeader = expectedHeadersOrdered[i];
            if ( ! expectedHeader.equals(actualHeader) ) {
                throw new IOException("Header columns mismatch in ordering.");
            }
        }

        super.captureHeader(reader); // Back to default processing if the headers include ordering are as expected
    }
}


    CustomHeaderColumnNameMappingStrategy yourMappingStrategy = new CustomHeaderColumnNameMappingStrategy<YourPOJO>();
    ourMappingStrategy.setType(YourPOJO.class);
    try {
        pojosFromCsv = new CsvToBeanBuilder<YourPOJO>(new FileReader(csvFile))
                .withType(YourPOJO.class)
                .withMappingStrategy(yourMappingStrategy)
                .build();
        pojosFromCsv.stream();

}

Вдохновлено использованием CaptureHeader в OpenCSV

person Philip Chan    schedule 04.05.2021