解決BufferedReader.readLine()遇見的坑
BufferedReader.readLine()遇見的坑
在寫ftp上傳文件至服務器的過程中,有這樣一個判斷:判斷某個文件夾下有多少個文件,內容為null的文件不上傳,所以利用BufferedReader讀取文件的內容,判斷是否為null,所以用到瞭BufferedReader.readLine(),結果竟然卡死:txt、word、Excle、Ftp文件等都沒有問題,但是讀取MP3、Rar、zip等文件時,就一直處於卡死狀態,先看代碼:
package com.test; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.Arrays; public class TestCh { public void readDocFileToFtp() { String docPath = "H:\\11"; // 文件所在路徑 模擬 File file; try { file = new File(docPath); File[] files = file.listFiles(); if (files.length == 0) { System.err.println(docPath + "文件夾下沒有任何文件!"); } else { Arrays.sort(files); System.err.println("文件數---" + files.length); for (int i = 0; i < files.length; i++) { if (files[i].isFile()) { InputStreamReader reader; reader = new InputStreamReader(new FileInputStream(files[i])); BufferedReader br = new BufferedReader(reader); String message = ""; String line = ""; long startTime = System.currentTimeMillis(); // 獲取開始時間 while ((line = br.readLine()) != null) { message += line; } br.close(); long endTime = System.currentTimeMillis(); // 獲取結束時間 System.out.println("程序運行時間: " + (endTime - startTime) / 1000 + "ms"); String fileName = files[i].getName(); if (message.trim() == null || message.length() == 0) { System.err.println(fileName + "文件內容為空!"); } else { // 上傳文件 System.err.println("上傳==============="); } } } } } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { TestCh te = new TestCh(); te.readDocFileToFtp(); } }
然後一直卡死:
我們都知道,readLine()方法是遇到換行符或者是對應流的結束符,該方法才會認為讀到瞭一行(才會結束其阻塞),讓程序繼續往下執行。但可能因為以前不留意,也沒遇見過這種情況,所以就認為該方法可放心使用
今天踩瞭這個坑,所以做個筆記
我們可能下意識地認為readLine()讀取到沒有數據時就返回null(因為read()方法當讀到沒有數據時返回-1),而實際上readLine()是一個阻塞函數,當沒有數據讀取時,就一直會阻塞在那,而不是返回null。
readLine()隻有在數據流發生異常或者另一端被close()掉時,才會返回null值。
如果不指定buffer大小,則readLine()使用的buffer有8192個字符。
在達到buffer大小之前,隻有遇到”/r”、”/n”、”/r/n”才會返回。
String readLine(boolean ignoreLF) throws IOException { StringBuffer s = null; int startChar; synchronized (lock) { ensureOpen(); boolean omitLF = ignoreLF || skipLF; bufferLoop: for (;;) { if (nextChar >= nChars) fill(); //在此讀數據 if (nextChar >= nChars) { /* EOF */ if (s != null && s.length() > 0) return s.toString(); else return null; } ......//其它 } private void fill() throws IOException { ..../其它 int n; do { n = in.read(cb, dst, cb.length - dst); //實質 } while (n == 0); if (n > 0) { nChars = dst + n; nextChar = dst; } }
通過查看源碼可知,readLine()是調用瞭read(char[] cbuf, int off, int len) 來讀取數據,後面再根據”/r”或”/n”來進行數據處理
所以使用readLine()一定要註意
1.讀入的數據要註意有/r或/n或/r/n
2.沒有數據時會阻塞,在數據流異常或斷開時才會返回null
3.非必要時(socket之類的數據流),要避免使用readLine(),以免為瞭等待一個換行/回車符而一直阻塞
BufferedReader.readLine解析
bufferedreader.readline()加載流程:
br = new BufferedReader(reader,510241024);//設置緩存大小:5M
根據指定緩存大小,或默認緩存大小,讀取文件內容放到緩存中,在將緩存數據放在內存中進行讀取,等前一批內存中的數據讀取完成後,
下一批緩存數據會放在內存中進行讀取;
按行讀取時等待讀取到換行符返回內容;
註意:以上內容都是自己理解的,僅為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 使用BufferedReader讀取TXT文件中數值,並輸出最大值
- java中使用Files.readLines()處理文本中行數據方式
- 聊聊為什麼要使用BufferedReader讀取File
- 關於BufferedReader的read()和readLine()的區別
- 關於BufferedReader的讀取效率問題