Java Socket读写缓存区Writer和Reader

Java Socket编程实例:[url]http://donald-draper.iteye.com/blog/2356695[/url]

在上一篇Java Socket编程实例,我们实战Java Socket编程中,用到
BufferedInput/OutputStream去包装Input/OutputStream读写socket的缓冲区,这种是通过
FilterInput/OutputStream方式;今天我们来看一下在HttpServletResponse中用的比较多的方式
PrintWriter/BufferedReader,即Writer/Reader方式。
服务器:

package socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Server
* @author donald
* 2017年2月13日
* 下午4:51:53
*/
public class TestServer {
public static final int PORT = 4003;

public static void main(String[] args) {
try {
startServer();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

// 服务端代码
public static void startServer() throws IOException, InterruptedException {
ServerSocket serverSocket = new ServerSocket(PORT);
System.out.println("服务器启动......");
while (true) {
Socket socket = serverSocket.accept();
// 获取输入流,并读取服务器端的响应信息
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String message = null;
while ((message = bufferedReader.readLine()) != null) {
System.out.println("收到客户端信息:" + message);
}
// 这里向网络进行两次写入
OutputStream outputStream = socket.getOutputStream();
// 将输出流包装为打印流
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.write("Welcome Client!");
printWriter.flush();
// 关闭输出流
socket.shutdownOutput();
// 关闭资源
bufferedReader.close();
inputStream.close();
printWriter.close();
outputStream.close();
socket.close();
}
}
}


客户端:

package socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* Client
* @author donald
* 2017年2月13日
* 下午4:52:27
*/
public class TestClient {
private static final int PORT = 4003;
private static final String ip = "192.168.132.126";

public static void main(String[] args) {
try {
client();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

public static void client() throws UnknownHostException, IOException {
// 创建socket连接
Socket socket = new Socket(ip, PORT);
System.out.println("连接服务器成功......");
// 这里向网络进行两次写入
OutputStream outputStream = socket.getOutputStream();
// 将输出流包装为打印流
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.write("Hello Server!");
printWriter.flush();
// 关闭输出流
socket.shutdownOutput();
// 获取输入流,并读取服务器端的响应信息
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String message = null;
while ((message = bufferedReader.readLine()) != null) {
System.out.println("收到服务端信息:" + message);
}
// 关闭资源
bufferedReader.close();
inputStream.close();
printWriter.close();
outputStream.close();
socket.close();

}
}


服务器端控制台输出:

服务器启动......
收到客户端信息:Hello Server!

客户端控制台输出:
连接服务器成功......
收到服务端信息:Welcome Client!

控制台的输出,不是我们今天所要探讨的,我们要关心的是下面这段代码
// 这里向网络进行两次写入
OutputStream outputStream = socket.getOutputStream();
// 将输出流包装为打印流
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.write("Hello Server!");
printWriter.flush();
// 关闭输出流
socket.shutdownOutput();
// 获取输入流,并读取服务器端的响应信息
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String message = null;
while ((message = bufferedReader.readLine()) != null) {
System.out.println("收到服务端信息:" + message);
}


这个分两部分来看1.PrintWriter,写缓冲区,2.BufferedReader,读缓冲区
第一部分:PrintWriter,写缓冲区

// 这里向网络进行两次写入
OutputStream outputStream = socket.getOutputStream();
// 将输出流包装为打印流
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.write("Hello Server!");
printWriter.flush();


从下面这句话开始
PrintWriter printWriter = new PrintWriter(outputStream);


public class PrintWriter extends Writer {

/**
* The underlying character-output stream of this
* <code>PrintWriter</code>.
*
* @since 1.2
*/
protected Writer out;//输出流

private final boolean autoFlush;//是否自动刷新缓冲区,默认为false
private boolean trouble = false;
private Formatter formatter;
private PrintStream psOut = null;
/**
* Line separator string. This is the value of the line.separator
* property at the moment that the stream was created.
* 系统默认换行符
*/
private final String lineSeparator;
}

构造PrintWriter
    public PrintWriter (Writer out) {
//委托给PrintWriter(OutputStream out, boolean autoFlush)
this(out, false);
}

根据OutputStream构造OutputStreamWriter,再包装成BufferedWriter
  public PrintWriter(OutputStream out, boolean autoFlush) {
//委托给PrintWriter(Writer out,boolean autoFlush)
this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush);
// save print stream for error propagation
if (out instanceof java.io.PrintStream) {
psOut = (PrintStream) out;
}
}

根据Writer(BufferedWriter)和autoFlush构造PrintWriter
  public PrintWriter(Writer out,boolean autoFlush) {
//初始化父类
super(out);
this.out = out;
this.autoFlush = autoFlush;
//初始化系统换行符
lineSeparator = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("line.separator"));
}

//Writer
public abstract class Writer implements Appendable, Closeable, Flushable {
/** Temporary buffer used to hold writes of strings and single characters */
private char[] writeBuffer;
/** Size of writeBuffer, must be >= 1*/
private final int writeBufferSize = 1024;
/**
* The object used to synchronize operations on this stream. For
* efficiency, a character-stream object may use an object other than
* itself to protect critical sections. A subclass should therefore use
* the object in this field rather than <tt>this</tt> or a synchronized
* method.
*/
protected Object lock;
/**
* Creates a new character-stream writer whose critical sections will
* synchronize on the writer itself.
*/
protected Writer() {
this.lock = this;
}

/**
* Creates a new character-stream writer whose critical sections will
* synchronize on the given object.
*
* @param lock
* Object to synchronize on
*/
//初始化Writer的同步锁,控制缓冲区的写操作
protected Writer(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
}

回到PrintWriter(OutputStream out, boolean autoFlush)方法的这一句
this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush);

先来看OutputStreamWriter
//OutputStreamWriter

public class OutputStreamWriter extends Writer {
private final StreamEncoder se;//输出字节流编码器
//构造OutputStreamWriter
public OutputStreamWriter(OutputStream out) {
//这个前面Writer看过
super(out);
try {
//初始化输出字节流编码器
se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);
} catch (UnsupportedEncodingException e) {
throw new Error(e);
}
}
}

//StreamEncoder
public class StreamEncoder extends Writer
{
private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
private volatile boolean isOpen;//输出流是否打开
private Charset cs;//字节编码集
private CharsetEncoder encoder;//字节编码器
private ByteBuffer bb;//字节缓冲区
private final OutputStream out;//输出流,从Socket获取的
private WritableByteChannel ch;/字节流通道
private boolean haveLeftoverChar;
private char leftoverChar;
private CharBuffer lcb;
static final boolean $assertionsDisabled = !sun/nio/cs/StreamEncoder.desiredAssertionStatus();
//初始化字符集,及输出流
public static StreamEncoder forOutputStreamWriter(OutputStream outputstream, Object obj, String s)
throws UnsupportedEncodingException
{
String s1;
s1 = s;
if(s1 == null)
s1 = Charset.defaultCharset().name();
if(Charset.isSupported(s1))
return new StreamEncoder(outputstream, obj, Charset.forName(s1));
break MISSING_BLOCK_LABEL_39;
IllegalCharsetNameException illegalcharsetnameexception;
illegalcharsetnameexception;
throw new UnsupportedEncodingException(s1);
}
private StreamEncoder(OutputStream outputstream, Object obj, Charset charset)
{
this(outputstream, obj, charset.newEncoder().onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE));
}
//初始化输出流是否打开状态,字节编码集,字节编码器,字节缓冲区,输出流
private StreamEncoder(OutputStream outputstream, Object obj, CharsetEncoder charsetencoder)
{
super(obj);
isOpen = true;
haveLeftoverChar = false;
lcb = null;
out = outputstream;
ch = null;
cs = charsetencoder.charset();
encoder = charsetencoder;
if(ch == null)
bb = ByteBuffer.allocate(8192);
}
}

再回到BufferedWriter的构造
this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush);

//BufferedWriter
public class BufferedWriter extends Writer {

private Writer out;
private char cb[];//缓存区
private int nChars, nextChar;//缓冲区大小,及写位置

private static int defaultCharBufferSize = 8192;//默认缓冲区大小

/**
* Line separator string. This is the value of the line.separator
* property at the moment that the stream was created.
*/
private String lineSeparator;

/**
* Creates a buffered character-output stream that uses a default-sized
* output buffer.
*
* @param out A Writer
*/
public BufferedWriter(Writer out) {
this(out, defaultCharBufferSize);
}

/**
* Creates a new buffered character-output stream that uses an output
* buffer of the given size.
*
* @param out A Writer
* @param sz Output-buffer size, a positive integer
*
* @exception IllegalArgumentException If sz is <= 0
*/
//初始化writer,缓冲区,缓冲区大小及位置和换行符
public BufferedWriter(Writer out, int sz) {
super(out);
if (sz <= 0)
throw new IllegalArgumentException("Buffer size <= 0");
this.out = out;
cb = new char[sz];
nChars = sz;
nextChar = 0;
lineSeparator = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("line.separator"));
}

这里我们小节一下PrintWriter:
构造PrintWriter实际为初始化writer和是否自动刷新缓存,及初始化换行符,同时
通过父类Writer,初始化写缓存同步锁;在构造PrintWriter的过程中,writer实际为
BufferedWriter,初始化BufferedWriter的过程,实际为初始化writer,缓冲区,缓冲区大小及位置和换行符,在构造BufferedWriter也需要传入writer,这个writer实际为OutputStreamWriter,OutputStreamWriter初始化主要是初始化字节流编码器,字节流编码器StreamEncoder初始化,实际为初始化输出流是否打开状态,字节编码集,
字节编码器,字节缓冲区,输出流OutputStream(从socket获取)。

构造PrintWriter到这里已经结束,下面来看一下如何发送字符串

printWriter.write("Hello Server!");


//PrintWriter
public void write(String s) {
write(s, 0, s.length());
}
public void write(String s, int off, int len) {
try {
synchronized (lock) {
//确保输出流打开
ensureOpen();
//out为BufferedWriter
out.write(s, off, len);
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}

//BufferedWriter
//发送字符串
public void write(String s, int off, int len) throws IOException {
synchronized (lock) {
ensureOpen();

int b = off, t = off + len;
while (b < t) {
int d = min(nChars - nextChar, t - b);
//将字符串发送字节流缓冲区中
s.getChars(b, b + d, cb, nextChar);
b += d;
nextChar += d;
if (nextChar >= nChars)
//如果缓存区已满,则发送缓存区
flushBuffer();
}
}
}
//刷新缓存
void flushBuffer() throws IOException {
synchronized (lock) {
ensureOpen();
if (nextChar == 0)
return;
//将缓存中数据发送出去,out为OutputStreamWriter
out.write(cb, 0, nextChar);
nextChar = 0;
}
}
//发送字节数组
public void write(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;
}

if (len >= nChars) {
/* If the request length exceeds the size of the output buffer,
flush the buffer and then write the data directly. In this
way buffered streams will cascade harmlessly. */
//如果字节流长度大于缓冲区大小则,刷新缓存区
flushBuffer();
//将缓存中数据发送出去,out为OutputStreamWriter
out.write(cbuf, off, len);
return;
}

int b = off, t = off + len;
while (b < t) {
int d = min(nChars - nextChar, t - b);
//将发送字节流,写入缓存区
System.arraycopy(cbuf, b, cb, nextChar, d);
b += d;
nextChar += d;
if (nextChar >= nChars)
//如果缓存区已满,则发送缓存区
flushBuffer();
}
}
}



//OutputStreamWriter

 public void write(char cbuf[], int off, int len) throws IOException {
//委托个字节流编码器
se.write(cbuf, off, len);
}

//StreamEncoder
//写缓存
public void write(char ac[], int i, int j)
throws IOException
{
label0:
{
synchronized(lock)
{
ensureOpen();
if(i < 0 || i > ac.length || j < 0 || i + j > ac.length || i + j < 0)
throw new IndexOutOfBoundsException();
if(j != 0)
break label0;
}
return;
}
//委托给implWrite
implWrite(ac, i, j);
obj;
JVM INSTR monitorexit ;
goto _L1
exception;
throw exception;
_L1:
}
//编码字节流
void implWrite(char ac[], int i, int j)
throws IOException
{
//将字节流,包装成CharBuffer
CharBuffer charbuffer = CharBuffer.wrap(ac, i, j);
if(haveLeftoverChar)
flushLeftoverChar(charbuffer, false);
do
{
if(!charbuffer.hasRemaining())
break;
//将包装后的字节流缓冲区,编码到字节流缓冲区bb(ByteBuffer)
CoderResult coderresult = encoder.encode(charbuffer, bb, false);
if(coderresult.isUnderflow())
{
if(!$assertionsDisabled && charbuffer.remaining() > 1)
throw new AssertionError(charbuffer.remaining());
if(charbuffer.remaining() == 1)
{
haveLeftoverChar = true;
leftoverChar = charbuffer.get();
}
break;
}
if(coderresult.isOverflow())
{
if(!$assertionsDisabled && bb.position() <= 0)
throw new AssertionError();
//如果字节流缓冲区bb(ByteBuffer)已满,则发送缓存数据
writeBytes();
} else
{
coderresult.throwException();
}
} while(true);
}
//发送缓存数据
private void writeBytes()
throws IOException
{
bb.flip();
int i = bb.limit();
int j = bb.position();
if(!$assertionsDisabled && j > i)
throw new AssertionError();
int k = j > i ? 0 : i - j;
if(k > 0)
if(ch != null)
{
if(ch.write(bb) != k && !$assertionsDisabled)
throw new AssertionError(k);
} else
{
//通过OutputStream发送字节流
out.write(bb.array(), bb.arrayOffset() + j, k);
}
bb.clear();
}

小节:
PrintWriter发送字符串,实际为将字符串通过BufferedWriter发送,BufferedWriter现将
字符串写入到其字节缓冲区中,如果缓冲区满,则发送缓存数据,发送委托给OutputStreamWriter,而OutputStreamWriter委托给StreamEncoder,有StreamEncoder将字节数组包装成CharBuffer,在通过编码器,编码字节到编码到字节流缓冲区bb(ByteBuffer),如果字节流缓冲区bb(ByteBuffer)已满,则发送缓存数据。

再来看
printWriter.flush();

//PrintWriter
public void flush() {
try {
synchronized (lock) {
ensureOpen();
out.flush();
}
}
catch (IOException x) {
trouble = true;
}
}

//BufferedWriter
public void flush() throws IOException {
synchronized (lock) {
//发送缓冲数据
flushBuffer();
out.flush();
}
}

//OutputStreamWriter

public void flush() throws IOException {
se.flush();
}

//StreamEncoder

public void flush()
throws IOException
{
synchronized(lock)
{
ensureOpen();
implFlush();
}
}
void implFlush()
throws IOException
{
implFlushBuffer();
if(out != null)
out.flush();
}
void implFlushBuffer()
throws IOException
{
if(bb.position() > 0)
//发送缓存数据
writeBytes();
}

从上来看PrintWriter的flush为发送缓存数据
最后来看一下
//PrintWriter
//新建一行
private void newLine() {
try {
synchronized (lock) {
ensureOpen();
//发送换行符,委托给BufferedWriter
out.write(lineSeparator);
if (autoFlush)
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
//BufferedWriter
public void newLine() throws IOException {
write(lineSeparator);
}

再来看如何输入流InputStream读取数据
第二部分:BufferedReader,读缓冲区

// 获取输入流,并读取服务器端的响应信息
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String message = null;
while ((message = bufferedReader.readLine()) != null) {
System.out.println("收到服务端信息:" + message);
}


先看InputStreamReader的构造
public class InputStreamReader extends Reader {
//流解码器
private final StreamDecoder sd;

/**
* Creates an InputStreamReader that uses the default charset.
*
* @param in An InputStream
*/
public InputStreamReader(InputStream in) {
super(in);
try {
//初始化流解码器
sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
} catch (UnsupportedEncodingException e) {
// The default encoding should always be available
throw new Error(e);
}
}
}

//StreamDecoder
public class StreamDecoder extends Reader
{
private static final int MIN_BYTE_BUFFER_SIZE = 32;//最小缓冲区大小
private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;//默认缓冲区大小
private volatile boolean isOpen;//输入流状态
private boolean haveLeftoverChar;
private char leftoverChar;
private static volatile boolean channelsAvailable = true;
private Charset cs;
private CharsetDecoder decoder;
private ByteBuffer bb;//字节流缓冲区
private InputStream in;//Socket 输入流
private ReadableByteChannel ch;
static final boolean $assertionsDisabled = !sun/nio/cs/StreamDecoder.desiredAssertionStatus();
//初始化字节集,构造StreamDecoder
public static StreamDecoder forInputStreamReader(InputStream inputstream, Object obj, String s)
throws UnsupportedEncodingException
{
String s1;
s1 = s;
if(s1 == null)
s1 = Charset.defaultCharset().name();
if(Charset.isSupported(s1))
return new StreamDecoder(inputstream, obj, Charset.forName(s1));
}
StreamDecoder(InputStream inputstream, Object obj, Charset charset)
{
this(inputstream, obj, charset.newDecoder().onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE));
}
//初始化输入流状态,字节流缓冲区,输入流
StreamDecoder(InputStream inputstream, Object obj, CharsetDecoder charsetdecoder)
{
super(obj);
isOpen = true;
haveLeftoverChar = false;
cs = charsetdecoder.charset();
decoder = charsetdecoder;
if(ch == null)
{
in = inputstream;
ch = null;
bb = ByteBuffer.allocate(8192);
}
bb.flip();
}
}

再看BufferedReader的构造
public class BufferedReader extends Reader {

private Reader in;//Reader

private char cb[];//缓冲区
private int nChars, nextChar;//缓冲区大小,及位置

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 */

/** If the next character is a line feed, skip it */
private boolean skipLF = false;

/** The skipLF flag when the mark was set */
private boolean markedSkipLF = false;

private static int defaultCharBufferSize = 8192;
private static int defaultExpectedLineLength = 80;
/**
* Creates a buffering character-input stream that uses a default-sized
* input buffer.
*
* @param in A Reader
*/
public BufferedReader(Reader in) {
this(in, defaultCharBufferSize);
}
//初始化缓冲区,缓冲区大小,及位置
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
public abstract class Reader implements Readable, Closeable {

protected Object lock;

/**
* Creates a new character-stream reader whose critical sections will
* synchronize on the given object.
* 创建读缓冲区同步锁
* @param lock The Object to synchronize on.
*/
protected Reader(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}

小节:
从InputStreamReader的构造实际上为初始化流解码器StreamDecoder,
StreamDecoder初始化主要是,初始化输入流状态,字节流缓冲区,socket输入流;
BufferedReader构造的主要是,初始化缓冲区,缓冲区大小,及位置和创建Reader读缓冲区同步锁

下面来看从socket输入流缓冲区,读取数据
String message = null;
while ((message = bufferedReader.readLine()) != null) {
System.out.println("收到服务端信息:" + message);
}

//BufferedReader
//从缓冲区读取一行数据
String readLine(boolean ignoreLF) throws IOException {
StringBuffer s = null;
int startChar;

synchronized (lock) {
ensureOpen();
boolean omitLF = ignoreLF || skipLF;

bufferLoop:
for (;;) {

if (nextChar >= nChars)
//填充BufferedReader缓冲区
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 '\n', if necessary */
if (omitLF && (cb[nextChar] == '\n'))
nextChar++;
skipLF = false;
omitLF = false;

charLoop:
for (i = nextChar; i < nChars; i++) {
c = cb[i];
if ((c == '\n') || (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);
}
}
}
//填充BufferedReader缓冲区
private void fill() throws IOException {
int dst;
//确定标记位置
if (markedChar <= UNMARKED) {
/* No mark */
dst = 0;
} else {
/* Marked */
int delta = nextChar - markedChar;
if (delta >= readAheadLimit) {
/* Gone past read-ahead limit: Invalidate mark */
markedChar = INVALIDATED;
readAheadLimit = 0;
dst = 0;
} else {
if (readAheadLimit <= cb.length) {
/* Shuffle in the current buffer */
System.arraycopy(cb, markedChar, cb, 0, delta);
markedChar = 0;
dst = delta;
} else {
/* Reallocate buffer to accommodate read-ahead limit */
char ncb[] = new char[readAheadLimit];
System.arraycopy(cb, markedChar, ncb, 0, delta);
cb = ncb;
markedChar = 0;
dst = delta;
}
nextChar = nChars = delta;
}
}

int n;
do {
//从InputStreamReader,读取数据到BufferedReader缓存区cb
//private char cb[];缓冲区
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}

//InputStreamReader
public int read(char cbuf[], int offset, int length) throws IOException {
//委托给StreamDecoder
return sd.read(cbuf, offset, length);
}

//StreamDecoder
//从输入流缓存读数据
public int read(char ac[], int i, int j)
throws IOException
{
...
i1 + implRead(ac, k, k + l);
...
}
int implRead(char ac[], int i, int j)
throws IOException
{
if(!$assertionsDisabled && j - i <= 1)
throw new AssertionError();
//包装socket输入流缓存数据为CharBuffer
CharBuffer charbuffer = CharBuffer.wrap(ac, i, j - i);
if(charbuffer.position() != 0)
charbuffer = charbuffer.slice();
boolean flag = false;
do
{
//解码包装后的字节流到字节流缓冲区ByteBuffer bb
CoderResult coderresult = decoder.decode(bb, charbuffer, flag);
if(coderresult.isUnderflow())
{
if(flag || !charbuffer.hasRemaining() || charbuffer.position() > 0 && !inReady())
break;
//读取缓存数据
int k = readBytes();
if(k >= 0)
continue;
flag = true;
if(charbuffer.position() == 0 && !bb.hasRemaining())
break;
decoder.reset();
continue;
}
if(coderresult.isOverflow())
{
if(!$assertionsDisabled && charbuffer.position() <= 0)
throw new AssertionError();
break;
}
coderresult.throwException();
} while(true);
if(flag)
decoder.reset();
if(charbuffer.position() == 0)
{
if(flag)
return -1;
if(!$assertionsDisabled)
throw new AssertionError();
}
return charbuffer.position();
}

//读取缓存数据

private int readBytes()
throws IOException
{
//这个我们放在以后说
bb.compact();
int l;
if(ch == null)
break MISSING_BLOCK_LABEL_48;
int i = ch.read(bb);
if(i >= 0)
break MISSING_BLOCK_LABEL_236;
l = i;
bb.flip();
return l;
int i1;
int j1;
int k1;
//获取缓存可读的字节数
int j = bb.limit();
//记录读取位置
l = bb.position();
if(!$assertionsDisabled && l > j)
throw new AssertionError();
i1 = l > j ? 0 : j - l;
if(!$assertionsDisabled && i1 <= 0)
throw new AssertionError();
//
j1 = in.read(bb.array(), bb.arrayOffset() + l, i1);
if(j1 >= 0)
break MISSING_BLOCK_LABEL_160;
k1 = j1;
//转换读写状态
bb.flip();
return k1;
if(j1 == 0)
throw new IOException("Underlying input stream returned zero bytes");
if(!$assertionsDisabled && j1 > i1)
throw new AssertionError((new StringBuilder()).append("n = ").append(j1).append(", rem = ").append(i1).toString());
bb.position(l + j1);
bb.flip();
}

从上面可以看出从缓存读取数据实际上,先从socket输入流缓冲区通过流解码器StreamDecoder读取数据,解码填充到BufferedReader缓冲区中,BufferedReader从缓冲区中,读取一行数据。

总结:
[color=green]构造PrintWriter实际为初始化writer和是否自动刷新缓存,及初始化换行符,同时
通过父类Writer,初始化写缓存同步锁;在构造PrintWriter的过程中,writer实际为
BufferedWriter,初始化BufferedWriter的过程,实际为初始化writer,
缓冲区,缓冲区大小及位置和换行符,在构造BufferedWriter也需要传入writer,
这个writer实际为OutputStreamWriter,OutputStreamWriter初始化主要是初始化字节流编码器,字节流编码器StreamEncoder初始化,实际为初始化输出流是否打开状态,字节编码集,
字节编码器,字节缓冲区,输出流OutputStream(从socket获取)。
PrintWriter发送字符串,实际为将字符串通过BufferedWriter发送,BufferedWriter现将
字符串写入到其字节缓冲区中,如果缓冲区满,则发送缓存数据,发送委托给OutputStreamWriter,而OutputStreamWriter委托给StreamEncoder,有StreamEncoder将字节数组包装成CharBuffer,在通过编码器,编码字节到编码到字节流缓冲区bb(ByteBuffer),如果字节流缓冲区bb(ByteBuffer)已满,则发送缓存数据。
InputStreamReader的构造实际上为初始化流解码器StreamDecoder,
StreamDecoder初始化主要是,初始化输入流状态,字节流缓冲区,socket输入流;
BufferedReader构造的主要是,初始化缓冲区,缓冲区大小,及位置和创建Reader读缓冲区同步锁。从缓存读取数据实际上,先从socket输入流缓冲区通过流解码器StreamDecoder读取数据,解码填充到BufferedReader缓冲区中,BufferedReader从缓冲区中,读取一行数据。[/color]


附:
/**
* Abstract class for writing to character streams. The only methods that a
* subclass must implement are write(char[], int, int), flush(), and close().
* Most subclasses, however, will override some of the methods defined here in
* order to provide higher efficiency, additional functionality, or both.
*
* @see Writer
* @see BufferedWriter
* @see CharArrayWriter
* @see FilterWriter
* @see OutputStreamWriter
* @see FileWriter
* @see PipedWriter
* @see PrintWriter
* @see StringWriter
* @see Reader
*
* @author Mark Reinhold
* @since JDK1.1
*/

public abstract class Writer implements Appendable, Closeable, Flushable {




[img]http://dl2.iteye.com/upload/attachment/0123/0445/ffd7b5eb-aa94-39b6-93ef-af3c4c4b9a23.png[/img]

package java.io;


/**
* Abstract class for reading character streams. The only methods that a
* subclass must implement are read(char[], int, int) and close(). Most
* subclasses, however, will override some of the methods defined here in order
* to provide higher efficiency, additional functionality, or both.
*
*
* @see BufferedReader
* @see LineNumberReader
* @see CharArrayReader
* @see InputStreamReader
* @see FileReader
* @see FilterReader
* @see PushbackReader
* @see PipedReader
* @see StringReader
* @see Writer
*
* @author Mark Reinhold
* @since JDK1.1
*/

public abstract class Reader implements Readable, Closeable {



[img]http://dl2.iteye.com/upload/attachment/0123/0447/8e4bf488-dfe4-3ed5-aa33-969bd84d2372.png[/img]


public abstract class ByteBuffer
extends Buffer
implements Comparable<ByteBuffer>
{

// These fields are declared here rather than in Heap-X-Buffer in order to
// reduce the number of virtual method invocations needed to access these
// values, which is especially costly when coding small buffers.
//
final byte[] hb; // Non-null only for heap buffers
final int offset;
boolean isReadOnly;
}


[img]http://dl2.iteye.com/upload/attachment/0123/0449/6fb89d13-3af2-344f-9110-804c9a4c2546.png[/img]

public abstract class CharBuffer
extends Buffer
implements Comparable<CharBuffer>, Appendable, CharSequence, Readable
{

// These fields are declared here rather than in Heap-X-Buffer in order to
// reduce the number of virtual method invocations needed to access these
// values, which is especially costly when coding small buffers.
//
final char[] hb; // Non-null only for heap buffers
final int offset;
boolean isReadOnly; // Valid only for heap buffers
}


[img]http://dl2.iteye.com/upload/attachment/0123/0451/75476d4c-a57c-39e6-bebd-7e4d02e4c897.png[/img]

public abstract class Buffer {

// Invariants: mark <= position <= limit <= capacity
private int mark = -1;
private int position = 0;
private int limit;
private int capacity;

// Used only by direct buffers
// NOTE: hoisted here for speed in JNI GetDirectBufferAddress
long address;
}



[img]http://dl2.iteye.com/upload/attachment/0123/0453/050e369a-c218-3dda-899d-b5fc62cee915.png[/img]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值