使用Files.lines遇到文件编码带bom的问题

参考:http://jybzjf.iteye.com/blog/2262392

java读取编码有bom文件之前是有bug,后来修复了。
但是JDK8中新增了Files的Stream操作好像依然不支持bom文件读取。

读取文件行数据使用的是Files.lines,使用方法如下:

//读取所有内容
List<String> lines = Files.readAllLines(Paths.get("g://test.txt"), Charsets.UTF_8);

//读取部分内容
long index = 0l;    //从0行开始读
int limit = 10;     //读取10行内容
Files.lines(Paths.get("g://test.txt"), Charsets.UTF_8)
                .skip(index)
                .limit(limit)
                .forEach(line -> {
                    //对每行内容做处理
                });

可以看到JDK8后使用Files的stream操作可以只用一行代码,甚至不用写文件输入输出流、缓冲就能方便读写文件。
但是也因此又出现了读写文件编码带bom的bug。

开篇参考链接里面的资料是java适配了编码带bom文件的读写,其中处理编码带bom文件的主要代码如下:

//注意:jdk8里,UnicodeInputStream类又有了一些细微的变化
File f  = new File("D:"+File.separator+"Order.txt");    
        FileInputStream in = new FileInputStream(f);    
        String dc  = Charset.defaultCharset().name();  
        UnicodeInputStream uin = new UnicodeInputStream(in,dc);  
        BufferedReader br = new BufferedReader(new InputStreamReader(uin));    
        String line = br.readLine();

UnicodeInputStream 就是处理带bom文件的处理类。
但是Files.lines都已经封装好了,参数只能传文件路径,并且也没有提供参数是文件流的接口。怎么处理呢?
接下来我们看下Files.lines方法源码。

public static Stream<String> lines(Path path, Charset cs) throws IOException {
        BufferedReader br = Files.newBufferedReader(path, cs);
        try {
            return br.lines().onClose(asUncheckedRunnable(br));
        } catch (Error|RuntimeException e) {
            try {
                br.close();
            } catch (IOException ex) {
                try {
                    e.addSuppressed(ex);
                } catch (Throwable ignore) {}
            }
            throw e;
        }
    }

源码里实际上也是对BufferedReader进行处理,既然如此我们可以在自己的代码这么用:

        UnicodeInputStream uis = new UnicodeInputStream(Files.newInputStream(Paths.get(path)), true);//true表示不读取bom字符
        BufferedReader br = new BufferedReader(new InputStreamReader(uis, charset));

        br.lines().onClose(asUncheckedRunnable(br))
                .skip(this.index)
                .limit(this.limit)
                .forEach(line -> {
                    System.out.pinrtln(line);
                });
        uis.close();

asUncheckedRunnable方法直接从源码里面拷出来

private static Runnable asUncheckedRunnable(Closeable c) {
        return () -> {
            try {
                c.close();
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        };
    }

这样就可以用Files的stream操作读取编码带bom的文件了。

猜你喜欢

转载自blog.csdn.net/ragin/article/details/78072261