Java读取文件时遇到\uFEFF首字符问题

需求


去除js文件注释中的外链。

分析


通过代码对文件内容过滤然后重新写入,所以需要分析外链存在的样式是什么样的,才能用合适的规则将其过滤。

这个问题的发现是在读取下面样式js代码遇到的,由于js代码又做过压缩处理,就两行:一行注释,一行源码:

/* jQuery.qrcode 0.11.0 - http://larsjung.de/jquery-qrcode/ - uses //github.com/kazuhikoarase/qrcode-generator (MIT) */
!function(){"use strict";function r(r,t,e,n){function...

所以为了过滤这样的外链,我编写的规则是这样的:

public static void copyFile(String source, String target) throws IOException {
    BufferedReader bufferedReader = new BufferedReader(new FileReader(source));
    BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(target));
    String val = bufferedReader.readLine();
    while (val != null) {
        // 过滤文件内容
        val = filterFileContent(val);
        bufferedWriter.write(val);
        bufferedWriter.newLine();
        bufferedWriter.flush();
        val = bufferedReader.readLine();
    }
    bufferedWriter.close();
    bufferedReader.close();
}


/**
  * 过滤的内容存在则返回true
  * @param val
  * @return
  */
public static String filterFileContent(String val) {
    String trimVal = val.trim();
    // 解决:/* Written by Alex Cicovic (http://www.alexcicovic.com) */
    if (trimVal.indexOf("/*") == 0  && trimVal.contains("*/")) {
        String[] split = trimVal.split("\\*/");
        // 为了避免 /* xxx */ assdsad 这种情况的误报
        if (split.length == 1) {
            return "";
        }
    }
}

执行着工具类期待着成功,但看到过滤后的文件发现并没有成功,很奇怪,代码是没有问题的,在其他的js文件中都是成功的。于是就开始进行调试
Java读取文件时遇到\uFEFF首字符问题_第1张图片
由于indexOf等于1,导致判断并没有匹配成功,这个结果很奇怪,当下的第一反应就是将js文件中的第一行注释取出来在代码中测试
Java读取文件时遇到\uFEFF首字符问题_第2张图片
这个结果才是跟预想的一致,但为什么读取出来的却不是0而是1呢,然后我开始调试了indexOf()代码,在调试的过程中发现可能是存在一个类似(取值的时候调用了trim()工具,所以才说类似)空格的字符导致的
在这里插入图片描述
在我准备查这个value参数的值是怎么来的时候,我又调试了编写规则的代码,这次是将文件读取的内容在控制台输出,然后再从文件中复制出来一份,两者进行匹配,但这个步骤还没有操作完成,就有了新的发现,可能这个就是导致问题出现的原因
控制台输出的内容:
在这里插入图片描述
然后将其复制出来放在代码中

String str = "\uFEFF/* jQuery.qrcode 0.11.0 - http://larsjung.de/jquery-qrcode/ - uses //github.com/kazuhikoarase/qrcode-generator (MIT) */";

原来是\uFEFF这个玩意搞得鬼,经过查阅相关资料有做这种解释:

  • 在Windows下用文本编辑器创建的文本文件,如果选择以UTF-8等格式保存,会在文件头(第一个字符)加入一个BOM标识。
  • 这个标识在Java读取文件的时候,不会被去掉,而且String.trim()也无法删除。如果用readLine()读取第一行存进String里面,这个String的length会比看到的大1,而且第一个字符就是这个BOM。

为了去掉这个标识,如果通过硬代码进行匹配替换肯定是不完美的,如果生成的jar在win上运行依旧是有问题的

// 硬编码进行过滤替换
if(line.startsWith("\uFEFF")){  
    //line = line.substring(1);  
    line = line.replace("\uFEFF", "");  
} 

在此可以借助第三方组件进行处理,利用apache commons io提供的BOMInputStream

<dependency>  
    <groupId>commons-iogroupId>  
    <artifactId>commons-ioartifactId>  
    <version>2.4version>  
dependency>     

代码示例:

public static void copyFile(String source, String target) throws IOException {
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new BOMInputStream(new FileInputStream(source))));
    BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(target));
    String val = bufferedReader.readLine();
    while (val != null) {
        // 过滤文件内容
        val = filterFileContent(val);
        bufferedWriter.write(val);
        bufferedWriter.newLine();
        bufferedWriter.flush();
        val = bufferedReader.readLine();
    }
    bufferedWriter.close();
    bufferedReader.close();
}

然后再次进行测试,问题终于成功解决
在这里插入图片描述
至于BOM是什么?

  • BOM = Byte Order Mark
  • BOM是Unicode规范中推荐的标记字节顺序的方法。比如说对于UTF-16,如果接收者收到的BOM是FEFF,表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。
    UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明“我是UTF-8编码”。BOM的UTF-8编码是EF BB BF(用UltraEdit打开文本、切换到16进制可以看到)。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。

参考:

https://blog.csdn.net/qq_21918903/article/details/78655790

你可能感兴趣的:(JAVA基础及工具使用,java,后端)