解決BufferedReader.readLine()遇見的坑
BufferedReader.readLine()遇見的坑
在寫ftp上傳文件至服務器的過程中,有這樣一個判斷:判斷某個文件夾下有多少個文件,內容為null的文件不上傳,所以利用BufferedReader讀取文件的內容,判斷是否為null,所以用到了BufferedReader.readLine(),結果竟然卡死:txt、word、Excle、Ftp文件等都沒有問題,但是讀取MP3、Rar、zip等文件時,就一直處于卡死狀態(tài),先看代碼:
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("文件數(shù)---" + 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()方法是遇到換行符或者是對應流的結束符,該方法才會認為讀到了一行(才會結束其阻塞),讓程序繼續(xù)往下執(zhí)行。但可能因為以前不留意,也沒遇見過這種情況,所以就認為該方法可放心使用
今天踩了這個坑,所以做個筆記
我們可能下意識地認為readLine()讀取到?jīng)]有數(shù)據(jù)時就返回null(因為read()方法當讀到?jīng)]有數(shù)據(jù)時返回-1),而實際上readLine()是一個阻塞函數(shù),當沒有數(shù)據(jù)讀取時,就一直會阻塞在那,而不是返回null。
readLine()只有在數(shù)據(jù)流發(fā)生異常或者另一端被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(); //在此讀數(shù)據(jù)
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) 來讀取數(shù)據(jù),后面再根據(jù)"/r"或"/n"來進行數(shù)據(jù)處理
所以使用readLine()一定要注意
1.讀入的數(shù)據(jù)要注意有/r或/n或/r/n
2.沒有數(shù)據(jù)時會阻塞,在數(shù)據(jù)流異?;驍嚅_時才會返回null
3.非必要時(socket之類的數(shù)據(jù)流),要避免使用readLine(),以免為了等待一個換行/回車符而一直阻塞
BufferedReader.readLine解析
bufferedreader.readline()加載流程:
br = new BufferedReader(reader,510241024);//設置緩存大小:5M
根據(jù)指定緩存大小,或默認緩存大小,讀取文件內容放到緩存中,在將緩存數(shù)據(jù)放在內存中進行讀取,等前一批內存中的數(shù)據(jù)讀取完成后,
下一批緩存數(shù)據(jù)會放在內存中進行讀??;
按行讀取時等待讀取到換行符返回內容;
注意:以上內容都是自己理解的,僅為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
WebSocket+Vue+SpringBoot實現(xiàn)語音通話的使用示例
本文主要介紹了WebSocket+Vue+SpringBoot實現(xiàn)語音通話的使用示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-11-11
Springboot 整合 Java DL4J 實現(xiàn)農(nóng)產(chǎn)品質量檢測系統(tǒng)(推薦)
本文詳細介紹了系統(tǒng)的搭建過程,包括技術選型、數(shù)據(jù)處理、模型訓練和評估等關鍵步驟,系統(tǒng)采用卷積神經(jīng)網(wǎng)絡,對水果成熟度和缺陷進行識別,有效解決了傳統(tǒng)方法成本高、效率低的問題,有助于提升農(nóng)產(chǎn)品檢測的科技含量和自動化水平2024-10-10
JavaWEB項目之如何配置動態(tài)數(shù)據(jù)源
這篇文章主要介紹了JavaWEB項目之如何配置動態(tài)數(shù)據(jù)源問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06
ShardingSphere jdbc集成多數(shù)據(jù)源的實現(xiàn)步驟
本文主要介紹了ShardingSphere jdbc集成多數(shù)據(jù)源的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-10-10
SpringMVC @RequestBody屬性名大寫字母注入失敗的解決
這篇文章主要介紹了SpringMVC @RequestBody屬性名大寫字母注入失敗的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04

