JAVA IO 의 Buffered Reader 소스 코드 분석
88997 단어 JAVABufferedReader소스 코드
**
BufferedReader 소개
* * Buffered Reader 는 버퍼 문자 입력 흐름 입 니 다.그것 은 Reader 에 계승 되 었 다.Buffered Reader 의 역할 은 다른 문자 의 입력 흐름 에 버퍼 기능 을 추가 하 는 것 입 니 다.BufferedReader 함수 목록
BufferedReader(Reader in)
BufferedReader(Reader in, int size)
void close()
void mark(int markLimit)
boolean markSupported()
int read()
int read(char[] buffer, int offset, int length)
String readLine()
boolean ready()
void reset()
long skip(long charCount)
**
BufferedReader 소스 코드 분석
**
public class BufferedReader extends Reader {
private Reader in;
//
private char cb[];
// nChars cb
// nextChar cb
private int nChars, nextChar;
// “ ”。 UNMARKED :
// (01) UNMARKED 。
// (02) INVALIDATED , , !
private static final int INVALIDATED = -2;
// “ ”
private static final int UNMARKED = -1;
// “ ”
private int markedChar = UNMARKED;
// “ ”
private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
// skipLF( skip Line Feed) “ ”
private boolean skipLF = false;
// “ ” , skipLF
private boolean markedSkipLF = false;
//
private static int defaultCharBufferSize = 8192;
//
private static int defaultExpectedLineLength = 80;
// “Reader” BufferedReader ,sz BufferedReader
public BufferedReader(Reader in, int sz) {
super(in);
if (sz <= 0)
throw new IllegalArgumentException("Buffer size <= 0");
this.in = in;
cb = new char[sz];
nextChar = nChars = 0;
}
// “Reader” BufferedReader , BufferedReader 8k
public BufferedReader(Reader in) {
this(in, defaultCharBufferSize);
}
// “BufferedReader”
private void ensureOpen() throws IOException {
if (in == null)
throw new IOException("Stream closed");
}
// 。 :
// (01) , fill() 。
// (02) , , fill() 。
private void fill() throws IOException {
// dst “cb ”。
int dst;
if (markedChar <= UNMARKED) {
// , dst=0。
dst = 0;
} else {
// delta “ ”, “ ” “ ” ;
int delta = nextChar - markedChar;
if (delta >= readAheadLimit) {
// “ ” “ (readAheadLimit)”,
// !
markedChar = INVALIDATED;
readAheadLimit = 0;
dst = 0;
} else {
if (readAheadLimit <= cb.length) {
// “ ” “ (readAheadLimit)”,
// “ (readAheadLimit)” / “ ”;
// “ , ” cb 。
System.arraycopy(cb, markedChar, cb, 0, delta);
markedChar = 0;
dst = delta;
} else {
// “ ” “ (readAheadLimit)”,
// “ (readAheadLimit)” “ ”;
// , “ , ” cb 。
char ncb[] = new char[readAheadLimit];
System.arraycopy(cb, markedChar, ncb, 0, delta);
cb = ncb;
markedChar = 0;
dst = delta;
}
// nextChar nChars
nextChar = nChars = delta;
}
}
int n;
do {
// “in” , cb ;
// cb dst , cb.length - dst
// n ; n==0( ), !
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
// “in” , nChars(cb )=dst+n,
// nextChar( )=dst。
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}
// BufferedReader , int
public int read() throws IOException {
synchronized (lock) {
ensureOpen();
for (;;) {
// “ ”,
// fill()
if (nextChar >= nChars) {
fill();
if (nextChar >= nChars)
return -1;
}
// “ ”,
// 。
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '
') {
nextChar++;
continue;
}
}
//
return cb[nextChar++];
}
}
}
// cbuf 。off cbuf ,len
private int read1(char[] cbuf, int off, int len) throws IOException {
// “ ”, 。
if (nextChar >= nChars) {
if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
return in.read(cbuf, off, len);
}
fill();
}
// , ; 。
if (nextChar >= nChars) return -1;
// “ ”,
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '
') {
nextChar++;
if (nextChar >= nChars)
fill();
if (nextChar >= nChars)
return -1;
}
}
//
int n = Math.min(len, nChars - nextChar);
System.arraycopy(cb, nextChar, cbuf, off, n);
nextChar += n;
return n;
}
// read1() , “ ” “ ”
public int read(char cbuf[], int off, int len) throws IOException {
synchronized (lock) {
ensureOpen();
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
int n = read1(cbuf, off, len);
if (n <= 0) return n;
while ((n < len) && in.ready()) {
int n1 = read1(cbuf, off + n, len - n);
if (n1 <= 0) break;
n += n1;
}
return n;
}
}
// 。ignoreLF “ ”
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;
}
boolean eol = false;
char c = 0;
int i;
/* Skip a leftover '
', if necessary */
if (omitLF && (cb[nextChar] == '
'))
nextChar++;
skipLF = false;
omitLF = false;
charLoop:
for (i = nextChar; i < nChars; i++) {
c = cb[i];
if ((c == '
') || (c == '\r')) {
eol = true;
break charLoop;
}
}
startChar = nextChar;
nextChar = i;
if (eol) {
String str;
if (s == null) {
str = new String(cb, startChar, i - startChar);
} else {
s.append(cb, startChar, i - startChar);
str = s.toString();
}
nextChar++;
if (c == '\r') {
skipLF = true;
}
return str;
}
if (s == null)
s = new StringBuffer(defaultExpectedLineLength);
s.append(cb, startChar, i - startChar);
}
}
}
// 。
public String readLine() throws IOException {
return readLine(false);
}
// n
public long skip(long n) throws IOException {
if (n < 0L) {
throw new IllegalArgumentException("skip value is negative");
}
synchronized (lock) {
ensureOpen();
long r = n;
while (r > 0) {
if (nextChar >= nChars)
fill();
if (nextChar >= nChars) /* EOF */
break;
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '
') {
nextChar++;
}
}
long d = nChars - nextChar;
if (r <= d) {
nextChar += r;
r = 0;
break;
}
else {
r -= d;
nextChar = nChars;
}
}
return n - r;
}
}
// “ ”
public boolean ready() throws IOException {
synchronized (lock) {
ensureOpen();
// true;
// , ,
if (skipLF) {
if (nextChar >= nChars && in.ready()) {
fill();
}
if (nextChar < nChars) {
if (cb[nextChar] == '
')
nextChar++;
skipLF = false;
}
}
return (nextChar < nChars) || in.ready();
}
}
// true。 BufferedReader mark(), reset()
public boolean markSupported() {
return true;
}
// BufferedReader 。 readAheadLimit , 。
public void mark(int readAheadLimit) throws IOException {
if (readAheadLimit < 0) {
throw new IllegalArgumentException("Read-ahead limit < 0");
}
synchronized (lock) {
ensureOpen();
// readAheadLimit
this.readAheadLimit = readAheadLimit;
//
markedChar = nextChar;
// “ ”
markedSkipLF = skipLF;
}
}
// BufferedReader ,
// mark() 。
public void reset() throws IOException {
synchronized (lock) {
ensureOpen();
if (markedChar < 0)
throw new IOException((markedChar == INVALIDATED)
? "Mark invalid"
: "Stream not marked");
nextChar = markedChar;
skipLF = markedSkipLF;
}
}
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
in.close();
in = null;
cb = null;
}
}
}
설명: BufferReader 의 소스 코드 를 읽 으 려 면 먼저 그의 사상 을 이해 해 야 한다.BufferReader 의 역할 은 다른 Reader 에 버퍼 기능 을 제공 하 는 것 입 니 다.BufferReader 를 만 들 때 구조 함 수 를 통 해 Reader 를 매개 변수 로 지정 합 니 다.BufferReader 는 버퍼 에 일부분 을 읽 을 때마다 이 Reader 의 데 이 터 를 분할 읽 습 니 다.버퍼 의 이 부분 데 이 터 를 조작 한 후 Reader 에서 다음 부분의 데 이 터 를 읽 습 니 다.왜 버퍼 링 이 필요 하지?원인 은 간단 하고 효율 적 인 문제!버퍼 의 데 이 터 는 실제 메모리 에 저장 되 어 있 으 며, 원본 데 이 터 는 하 드 디스크 나 NandFlash 에 저 장 될 수 있 습 니 다.메모리 에서 데 이 터 를 읽 는 속도 가 하 드 디스크 에서 데 이 터 를 읽 는 속도 보다 최소 10 배 이상 빠르다 는 것 을 잘 알 고 있다.그럼 왜 모든 데 이 터 를 한꺼번에 버퍼 에 읽 지 않 았 습 니까?첫째, 모든 데 이 터 를 읽 는 데 걸 리 는 시간 이 길 수 있 습 니 다.둘째, 메모리 가격 이 매우 비 싸 서 용량 이 하드디스크 만큼 크 고 싶 지 않다.
fill () 함수 에 대해 네 가지 상황 으로 나 누 어 설명 합 니 다.
**
상황 1: 버퍼 의 데 이 터 를 읽 었 고 버퍼 가 표시 되 지 않 았 습 니 다.
* * 실행 절 차 는 다음 과 같 습 니 다. (01) 다른 함수 가 fill () 을 호출 하여 버퍼 의 데이터 (02) fill () 실행 코드 if (markedChar < = UNMARKED) {...} 를 업데이트 합 니 다. 분석 하기 편리 하도록 이러한 상황 에서 fill () 이 실행 하 는 작업 은 다음 코드 와 같 습 니 다.
private void fill() throws IOException {
int dst;
if (markedChar <= UNMARKED) {
/* No mark */
dst = 0;
}
int n;
do {
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}
설명: 이러한 상황 이 발생 하 는 상황 은 Reader 에 긴 데이터 가 있 습 니 다. 우 리 는 그 중에서 일부 데 이 터 를 읽 고 버퍼 에서 작업 을 합 니 다.버퍼 에 있 는 데 이 터 를 읽 을 때마다 Buffered Reader 가 표시 되 지 않 습 니 다.그러면 이어서 Reader (BufferReader 가 버퍼 기능 을 제공 하 는 Reader) 에서 다음 부분의 데 이 터 를 버퍼 로 읽 습 니 다.이 가운데 버퍼 에 있 는 데 이 터 를 다 읽 었 는 지 여 부 를 판단 하 는 것 은 'nextChar 와 nChars 사이 의 크기 비교' 를 통 해 판단 된다.그 중에서 nChars 는 버퍼 에 있 는 문자 의 총 갯 수 이 고 nextChar 는 버퍼 에 있 는 다음 읽 을 문자 의 위치 입 니 다.버 프 레 드 리더 가 표 시 됐 는 지 판단 하 는 것 은 'markedChar' 를 통 해 판단 된다.이 사상 을 이해 한 후에 우 리 는 이런 상황 에서 fill () 의 코드 를 분석 하면 특히 이해 하기 쉽다.(01) if (markedChar < = UNMARKED) 는 'Buffered Reader 가 표시 되 었 는 지' 를 판단 하 는 역할 을 합 니 다.표 시 될 경우 dst = 0.(02) in. read (cb, dst, cb. length - dst) 는 in. read (cb, 0, cb. length) 와 같 습 니 다. Reader 대상 in 에서 cb. length 데 이 터 를 읽 고 버퍼 cb 에 저장 하 며 버퍼 cb 의 위치 0 부터 저장 한 다 는 뜻 입 니 다.이 함수 의 반환 값 은 n 과 같 습 니 다. 즉, n 은 실제 읽 은 문자 의 개 수 를 표시 합 니 다.n = 0 (즉 데 이 터 를 읽 지 못 했 음) 은 데 이 터 를 읽 을 때 까지 계속 읽 습 니 다.(03) nChars = dst + n 은 nChars = n 과 같다.버퍼 데이터 cb 를 업데이트 한 후 nChars (버퍼 의 데이터 개수) 를 n 으로 설정 합 니 다.(04) nextChar = dst 등 가 는 nextChar = 0;버퍼 데이터 cb 를 업데이트 한 후 nextChar (버퍼 에서 다음 읽 을 문자 의 색인 값) 를 0 으로 설정 합 니 다.
**
상황 2: 버퍼 의 데 이 터 를 읽 었 습 니 다. 버퍼 의 태그 위치 > 0, 그리고 "현재 태그 의 길이" 가 "태그 상한 선 (readAhead Limit)" 을 초과 합 니 다.
* * 실행 절 차 는 다음 과 같 습 니 다. (01) 다른 함수 가 fill () 을 호출 하여 버퍼 의 데이터 (02) fill () 실행 코드 if (della > = readAhead Limit) {...} 를 업데이트 합 니 다. 분석 하기 편리 하도록 이러한 상황 에서 fill () 이 실행 하 는 작업 은 다음 코드 와 같 습 니 다.
private void fill() throws IOException {
int dst;
if (markedChar > UNMARKED) {
int delta = nextChar - markedChar;
if (delta >= readAheadLimit) {
markedChar = INVALIDATED;
readAheadLimit = 0;
dst = 0;
}
}
int n;
do {
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}
설명: 이러한 상황 이 발생 하 는 상황 은 Buffered Reader 에 긴 데이터 가 있 습 니 다. 우 리 는 그 중에서 일부 데 이 터 를 읽 고 버퍼 에 가서 작업 을 합 니 다.버퍼 에 있 는 데 이 터 를 읽 은 후에 BufferedReader 에 태그 가 존재 할 때 '현재 태그 의 길이' 는 '태그 상한 선' 보다 큽 니 다.그럼 상황 2.이 때, 우 리 는 '태그' 를 버 리 고 버퍼 를 업데이트 합 니 다.(01) delta = nextChar - markedChar;그 중에서 dela 는 '현재 표 시 된 길이' 입 니 다. '다음 읽 힌 문자 의 위치' 에서 '표 시 된 위치' 의 차 이 를 줄 입 니 다.(02) if (delta >= readAheadLimit);그 중에서 dela > = readAhead Limit 은 '현재 표 시 된 길이' > = '표시 상한 선' 을 의미 합 니 다.왜 상한 선 을 표시 해 야 합 니까? 즉, read Ahead Limit 의 값 은 도대체 어떤 의미 가 있 습 니까?우리 가 위 치 를 표시 한 후에 버퍼 를 업데이트 할 때 표 시 된 위 치 는 저 장 됩 니 다.버퍼 를 계속 업데이트 할 때 표 시 된 위 치 는 계속 확 대 됩 니 다.그리고 메모리 의 용량 은 유효 합 니 다. 우 리 는 길이 의 저장 표 시 를 제한 하지 않 을 수 없습니다.그래서 표지 의 길 이 를 제한 하기 위해 readAhead Limit 가 필요 합 니 다!(03) in. read (cb, dst, cb. length - dst) 는 in. read (cb, 0, cb. length) 와 같 습 니 다. Reader 대상 in 에서 cb. length 데 이 터 를 읽 고 버퍼 cb 에 저장 하 며 버퍼 cb 의 위치 0 부터 저장 한 다 는 뜻 입 니 다.이 함수 의 반환 값 은 n 과 같 습 니 다. 즉, n 은 실제 읽 은 문자 의 개 수 를 표시 합 니 다.n = 0 (즉 데 이 터 를 읽 지 못 했 음) 은 데 이 터 를 읽 을 때 까지 계속 읽 습 니 다.(04) nChars = dst + n 은 nChars = n 과 같다.버퍼 데이터 cb 를 업데이트 한 후 nChars (버퍼 의 데이터 개수) 를 n 으로 설정 합 니 다.(05) nextChar = dst 등 가 는 nextChar = 0 이다.버퍼 데이터 cb 를 업데이트 한 후 nextChar (버퍼 에서 다음 읽 을 문자 의 색인 값) 를 0 으로 설정 합 니 다.
**
상황 3: 버퍼 의 데 이 터 를 읽 었 습 니 다. 버퍼 의 표시 위치 > 0, "현재 표 시 된 길이" 는 "표시 상한 선 (readAhead Limit)" 을 초과 하지 않 았 으 며, "표시 상한 선 (readAhead Limit)" 은 "버퍼 의 길이" 보다 작 습 니 다.
* * 실행 절 차 는 다음 과 같 습 니 다. (01) 다른 함수 호출 fill () 은 버퍼 의 데이터 (02) fill () 실행 코드 if (readAhead Limit < = cb. length) {..} 를 업데이트 합 니 다. 분석 하기 편리 하도록 이러한 상황 에서 fill () 이 실행 하 는 작업 은 다음 코드 와 같 습 니 다.
private void fill() throws IOException {
int dst;
if (markedChar > UNMARKED) {
int delta = nextChar - markedChar;
if ((delta < readAheadLimit) && (readAheadLimit <= cb.length) ) {
System.arraycopy(cb, markedChar, cb, 0, delta);
markedChar = 0;
dst = delta;
nextChar = nChars = delta;
}
}
int n;
do {
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}
설명: 이러한 상황 이 발생 하 는 상황 은 Buffered Reader 에 긴 데이터 가 있 습 니 다. 우 리 는 그 중에서 일부 데 이 터 를 읽 고 버퍼 에 가서 작업 을 합 니 다.버퍼 에 있 는 데 이 터 를 읽 은 후에 BufferedReader 에 태그 가 존재 할 때 '현재 태그 의 길이' 는 '태그 상한 선' 보다 작고 '태그 상한 선' 은 '버퍼 길이' 보다 작 습 니 다.그럼 상황 3.이때 저 희 는 '표 시 된 위치' (즉, 표 시 된 위치 에서 시 작 된 데 이 터 를 유지 하 는 것) 를 보류 하고 버퍼 를 업데이트 합 니 다 (추 가 된 데 이 터 를 보 존 된 데이터 에 추가 합 니 다).
**
상황 4: 버퍼 의 데 이 터 를 읽 었 습 니 다. 버퍼 의 표시 위치 > 0, "현재 표 시 된 길이" 는 "표시 상한 선 (readAhead Limit)" 을 초과 하지 않 았 고 "표시 상한 선 (readAhead Limit)" 은 "버퍼 의 길이" 보다 큽 니 다.
* * 실행 절 차 는 다음 과 같 습 니 다. (01) 다른 함수 가 fill () 을 호출 하여 버퍼 의 데이터 (02) fill () 실행 코드 else {char ncb [] = new char [readAhead Limit] 를 업데이트 합 니 다...} 분석 하기 편리 하도록 이러한 상황 에서 fill () 이 실행 하 는 작업 은 다음 코드 와 같 습 니 다.
private void fill() throws IOException {
int dst;
if (markedChar > UNMARKED) {
int delta = nextChar - markedChar;
if ((delta < readAheadLimit) && (readAheadLimit > cb.length) ) {
char ncb[] = new char[readAheadLimit];
System.arraycopy(cb, markedChar, ncb, 0, delta);
cb = ncb;
markedChar = 0;
dst = delta;
nextChar = nChars = delta;
}
}
int n;
do {
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}
설명: 이러한 상황 이 발생 하 는 상황 은 Buffered Reader 에 긴 데이터 가 있 습 니 다. 우 리 는 그 중에서 일부 데 이 터 를 읽 고 버퍼 에 가서 작업 을 합 니 다.버퍼 에 있 는 데 이 터 를 읽 은 후에 BufferedReader 에 태그 가 존재 할 때 '현재 태그 의 길이' 는 '태그 상한 선' 보다 작고 '태그 상한 선' 은 '버퍼 길이' 보다 큽 니 다.그럼 상황이 때 우 리 는 버퍼 의 크기 를 업데이트 한 다음 에 '표 시 된 위치' (즉, 표 시 된 위치 에서 시 작 된 데 이 터 를 유지 하 는 것) 를 유지 하고 버퍼 데 이 터 를 업데이트 해 야 한다.
**
예제 코드
**
BufferedReader API , (BufferedReaderTest.java):
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.lang.SecurityException;
/**
* BufferedReader
*
* @author skywang
*/
public class BufferedReaderTest {
private static final int LEN = 5;
public static void main(String[] args) {
testBufferedReader() ;
}
/**
* BufferedReader API
*/
private static void testBufferedReader() {
// BufferedReader , ArrayLetters
try {
File file = new File("bufferedreader.txt");
BufferedReader in =
new BufferedReader(
new FileReader(file));
// 5 。“abcde”
for (int i=0; i<LEN; i++) {
// ,
if (in.ready()) {
// “ ”
int tmp = in.read();
System.out.printf("%d : %c
", i, tmp);
}
}
// “ ” ,
if (!in.markSupported()) {
System.out.println("make not supported!");
return ;
}
// “ ”, 6 --“f”
// 1024 marklimit
in.mark(1024);
// 22 。
in.skip(22);
// 5
char[] buf = new char[LEN];
in.read(buf, 0, LEN);
System.out.printf("buf=%s
", String.valueOf(buf));
//
System.out.printf("readLine=%s
", in.readLine());
// “ ” mark() , “f” 。
in.reset();
// “ ” 5 buf 。 “fghij”
in.read(buf, 0, LEN);
System.out.printf("buf=%s
", String.valueOf(buf));
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
프로그램 에서 읽 은 bufferedreader. txt 의 내용 은 다음 과 같 습 니 다.
abcdefghijklmnopqrstuvwxyz
0123456789
ABCDEFGHIJKLMNOPQRSTUVWXYZ
실행 결과:
0 : a
1 : b
2 : c
3 : d
4 : e
buf=01234
readLine=56789
buf=fghij
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JAVA 객체 작성 및 제거 방법정적 공장 방법 정적 공장 방법의 장점 를 반환할 수 있습니다. 정적 공장 방법의 단점 류 공유되거나 보호된 구조기를 포함하지 않으면 이불류화할 수 없음 여러 개의 구조기 파라미터를 만났을 때 구축기를 고려해야 한다...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.