前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >读取含有BOM头的文件遇到的问题

读取含有BOM头的文件遇到的问题

作者头像
欠扁的小篮子
发布2018-04-11 11:28:38
1.6K0
发布2018-04-11 11:28:38
举报
文章被收录于专栏:技术碎碎念技术碎碎念

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

解析配置文件的方法。

代码语言:javascript
复制
 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的方法:

代码语言:javascript
复制
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头:

代码语言:javascript
复制
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头的方式推荐

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-02-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档