Java 如何在打开的csv中获取和验证csv标头?

Java 如何在打开的csv中获取和验证csv标头?,java,spring-boot,opencsv,Java,Spring Boot,Opencsv,我想从csv文件中获取头文件。如果我不使用这个skipline,那么我将在0索引数组中获取标题。但我想使用HeaderColumnNameMappingStrategy直接获取头文件,但它不适用于我的代码 我还想验证标题列列表(比如csv不允许包含额外的列) 我也检查过这个,但对我没有帮助 @SuppressWarnings({ "unchecked", "rawtypes" }) public Map<String, Object> handleStockFileUpload(Mu

我想从csv文件中获取头文件。如果我不使用这个skipline,那么我将在0索引数组中获取标题。但我想使用HeaderColumnNameMappingStrategy直接获取头文件,但它不适用于我的代码

我还想验证标题列列表(比如csv不允许包含额外的列)

我也检查过这个,但对我没有帮助

@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;
}
@SuppressWarnings({“unchecked”,“rawtypes”})
公共地图handleStockFileUpload(多部分文件,长customerId){
Map responseMap=newhashmap();
responseMap.put(“数据映射”,“数据映射”);
响应映射放置(“errormap”和“);
响应映射放置(“错误键”,“错误键”);
列表=新的ArrayList();
List csvStockList=newarraylist();
试一试{
字符串文件名=新的SimpleDataFormat(“yyyy_-MM_-dd_-HHmmss”).format(新日期())+“_”+文件.getOriginalFilename();
responseMap.put(“文件名”,文件名);
文件stockFile=新文件(productsUploadFilePath+文件名);
stockFile.getParentFile().mkdirs();
FileOutputStream fos=新的FileOutputStream(stockFile);
fos.write(file.getBytes());
fos.close();
CsvTransfer CsvTransfer=新CsvTransfer();
ColumnPositionMappingStrategy ms=新ColumnPositionMappingStrategy();
ms.setType(StockCsv.class);
Reader Reader=Files.newbuffereder(path.get(productsUploadFilePath+fileName));
CSVReader CSVReader=新的CSVReader(读卡器);
CsvToBean cb=新的CsvToBeanBuilder(读卡器)
.withType(StockCsv.class)
.withMappingStrategy(ms)
.基普林斯(1)
.build();
setCsvList(cb.parse());
reader.close();
csvStockList=csvTransfer.getCsvList();
}捕获(例外e){
e、 printStackTrace();
响应映射put(“状态”、“服务器错误”);
}
响应映射put(“数据映射”,csvStockList);
返回响应映射;
}

这里有一个解决当前问题的替代方案。首先,定义您希望的标题外观。例如:

publicstaticfinalarraylistfileformat=新的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;

}
public String validateCsvFileDetails(多部分文件文件,Set requiredHeadersArray){
Set errors=new HashSet();
试一试{
InputStream=file.getInputStream();
BufferedReader reader=新的BufferedReader(新的InputStreamReader(流));
字符串headerLine=reader.readLine();
if(Objects.isNull(headerLine))
return“文件没有头,请确保上传格式正确”;
列表标题列表;
字符串[]headersInFileArray;
if(headerLine.contains(“,”)){
headersInFileArray=StringUtils.split(headerLine,“,”);
headersInFileList=Arrays.asList(headersInFileArray);
}else//headerline只有一个headerfield
{
headersinflelist=集合。单例列表(headerLine);
}
for(字符串头:requiredHeadersArray){
如果(!headersInFileList.contains(header))
错误。添加(“文件的标题格式错误,请确保存在“+标题+”标题”);
}
//如果有错误,请返回它
如果(!errors.isEmpty())
返回sysUtils.getStringFromSet(错误);
//确保csv文件在标题后实际有值,但不要读取超过第一行的内容
弦线;
int计数器=0;
而((line=reader.readLine())!=null){
计数器++;
如果(计数器>0)
打破
}
//如果行为null,则返回验证错误
if(Objects.isNull(行))
返回“不能上传空文件”;
}捕获(例外e){
logger.error(新对象(){
}.getClass().GetEnclosuringMethod().getName(),e);
返回“系统错误”;
}
返回null;
}
现在,您可以按如下方式验证文件头:

  String errors = validateCsvFileDetails(file, new HashSet<>(fileFormat));
     if (errors != null)
        return error
    //proceed
String errors=validateCsvFileDetails(文件,新的HashSet(fileFormat));
如果(错误!=null)
返回错误
//进行

在这里,我将我的csvHeader与原始Header进行比较:

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;
  }
List originalHeader=fileUploadUtility.getHeader(new StockCsv());
List invalidHeader=csvHeader.stream().filter(o->(originalHeader.stream().filter(f->f.equalsIgnoreCase(o)).count())<1.collect(collector.toList());
if(null!=invalidHeader&&invalidHeader.size()>0&&invalidHeader.toString().replaceAll(“\\[\\]”,”).length()>0){
msg=“无效列:”+invalidHeader.toString()。替换(“,]”,“]”+”。请从文件中删除无效列。“;
结果映射put(1,msg);
}
公共列表getHeader(T pojo){
//TODO自动生成的方法存根
最终CustomMappingStrategy mappingStrategy=新CustomMappingStrategy();

mappingStrategy.setType((Class我找到了以下解决方案:

  • 将@CsvBindByName与HeaderColumnNameMappingStrategy一起使用,例如,使用@CsvBindByName注释bean属性:
  • 添加如下方法:
  • 公共类CsvParser{
    公共ParseResult parseByPropertyNames(读卡器csvReader,类beanClass)引发IOException{
    CSVReader reader=新的CSVReaderBuilder(CSVReader)。带有CSVParser(新
    CSVParserBuilder().build()).build();
    CsvToBean=新的CsvToBean();
    HeaderColumnNameMappingStrategy mappingStrategy=新建HeaderColumnNameMappingStrategy();
    mappingStrategy.setType(beanClass);
    setMappingStrategy(mappingStrategy);
    setCsvReader(读卡器);
    listbeans=bean.parse();
    返回新的CsvParseResult(mappingStrategy.generateHeader(),bean);
    }
    
        public static class HollywoodActor {
            private int id;
            @CsvBindByName(column = "First Name")
            private String firstName;
            @CsvBindByName(column = "Last Name")
            private String lastName;
        // getter / setter
        }
    
        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);
            }
    
    
        public class ParseResult <T> {
          private final String[] headers;
          private final List<T> lines;
          // all-args constructor & getters
        }
    
        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)));
    
    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();