參考: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的檔案了。