zoukankan      html  css  js  c++  java
  • 读取含有BOM头的文件遇到的问题

    需求是读取一个csv文件,然后解析成对应的数据结构。csv必须包含指定的某些列,通过列名header来进行校验。

    解析配置文件的方法。

     1 public List<QuestionData> buildConfigData(final MultipartFile file) {
     2 
     3     CsvReader csvReader = null;
     4     List<QuestionData> questionDataList;
     5     try (DataInputStream inputStream = new DataInputStream(file.getInputStream())) {
     6         csvReader = new CsvReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
     7 
     8         if (!csvReader.readHeaders()) {
     9             return Lists.newLinkedList();
    10         }
    11 
    12         final String[] headers = csvReader.getHeaders();
    13         getAndCheckHeader(headers);
    14         questionDataList = getQuestionData(csvReader, headers);
    15 
    16     } catch (final IOException e) {
    17         log.error("解析配置文件错误", e);
    18         throw new FatalException("解析配置文件错误");
    19     } finally {
    20         if (csvReader != null) {
    21             csvReader.close();
    22         }
    23     }
    24     return questionDataList;
    25 }

    其中,检查header的方法:

    private static final Set<String> NEEDED_COLUMNS = ImmutableSet
            .of(QuestionDataType.ORDER.name(), QuestionDataType.DESC.name(), QuestionDataType.OPTION_A.name(),
                    QuestionDataType.OPTION_B.name(), QuestionDataType.OPTION_C.name(), QuestionDataType.ANSWER.name());
    
    private void getAndCheckHeader(final String[] headers) {
        //某些必要的列不存在
        HashSet<String> sets = Sets.newHashSet(headers);
        if (!sets.containsAll(NEEDED_COLUMNS)) {
            throw new FatalException("缺少必要的列信息");
        }
    }

    实际出现的问题是,上传文件的时候总是出现缺少必要的列信息这个异常。debug发现,containsAll这个方法一直返回false,但是看NEEDED_COLUMNS里面的字符串,在header里面都存在,例如ORDER字符串:

    从这里看,headers里面有ORDER字符串,但是NEEDED_COLUMNS.contains(headers[0])返回的结果就是false。

    debug时使用evaluate,将headers[0]的value  copy一下,粘贴到输入框里,就发现了问题:

     

    可以看的出来,headers[0]的实际值是"uFEFFORDER",而非"ORDER",前面多了一个"uFEFF"。

    经查,"uFEFF"是BOM头,windows下保存文件时经常会插入在字符串最前面,debug时直接看值是看不出来有这个BOM头的。

    解决方案,使用apache的BOMInputStream,可以过滤掉BOM头:

    public List<QuestionData> buildConfigData(final MultipartFile file) {
    
        CsvReader csvReader = null;
        List<QuestionData> questionDataList;
    
        //过滤BOM头
        try (BOMInputStream inputStream =  new BOMInputStream(file.getInputStream())) {
            csvReader = new CsvReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
    
            if (!csvReader.readHeaders()) {
                return Lists.newLinkedList();
            }
    
            final String[] headers = csvReader.getHeaders();
            getAndCheckHeader(headers);
            questionDataList = getQuestionData(csvReader, headers);
    
        } catch (final IOException e) {
            log.error("解析配置文件错误", e);
            throw new FatalException("解析配置文件错误");
        } finally {
            if (csvReader != null) {
                csvReader.close();
            }
        }
        return questionDataList;
    }

    使用BOMInputStream,将原有的InputSteam包一层即可。

    参考文章:Java处理文件BOM头的方式推荐

  • 相关阅读:
    Jmeter压测
    .NET .Core 选择日志框架
    边缘控制器在边缘计算中的作用
    为何选择NB-IOT,NB-IOT的特点是什么
    RS232协议是什么
    物联网在生活中的应用场景
    透传模块是什么 为何透传
    4G DTU相对于GPRS/3G DTU有什么优势
    MQTT协议和Modbus之间的区别是什么
    4G模块应该怎么选择
  • 原文地址:https://www.cnblogs.com/z941030/p/8482478.html
Copyright © 2011-2022 走看看