Java 如何在打开的csv中获取和验证csv标头?
我想从csv文件中获取头文件。如果我不使用这个skipline,那么我将在0索引数组中获取标题。但我想使用HeaderColumnNameMappingStrategy直接获取头文件,但它不适用于我的代码 我还想验证标题列列表(比如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
@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();