文章目录
1 InputStream 子类结构1.1 InputStream 源码分析
2 InputStream 具体实现类源码分析2.1 ByteArrayInputStream —— 字节输入流2.2 FileInputStream —— 文件输入流2.3 PipedInputStream —— 管道输入流2.4 ObjectInputStream —— Java 反序列化输入流2.4.1 BlockDataInputStream2.4.2 PeekInputStream
2.5 SocketInputStream —— 网络输入流
3 Inputstream 装饰者类源码分析3.1 BufferedInputStream —— 缓冲输入流3.2 DataInputStream —— 基本类型反序列化输入流3.3 GZIPInputStream —— 读取GZIP 格式输入流3.4 ZIPInputStream —— 读取ZIP 格式输入流
1 InputStream 子类结构
下图是 InputStream 及其子类的结构图。可以看出 InputStream 是一个典型的装饰者模式的示例InputStream:抽象的组件类,具体的组件类继承它,来实现不同的输入流功能FilterInputStream:抽象装饰者类,具体装饰者类继承它,来对它包装的组件类,进行扩展Java IO 的扩展:
添加具体组件类,实现特定的输入流功能添加具体装饰类,达到保证组件类的目的
1.1 InputStream 源码分析
inputStream抽象类功能
定义读取一个字节 或 多个字节的 方法定义了 mark、reset 的方法,由具体子类实现 重复读取一段数据流的功能定义了关闭输入流的方法定义了返回剩余可读取字节的方法注: 只有读取一个字节的 read() 方法是抽象的,也就是说,具体类只要实现这一个方法即可,其它的可不实现
public abstract class InputStream implements Closeable {
public abstract int read() throws IOException
;
public int read(byte b
[]) throws IOException
{
return read(b
, 0, b
.length
);
}
public int read(byte b
[], int off
, int len
) throws IOException
{...}
public long skip(long n
) throws IOException
{...}
public int available() throws IOException
{
return 0;
}
public void close() throws IOException
{}
public synchronized void mark(int readlimit
) {}
public synchronized void reset() throws IOException
{
throw new IOException("mark/reset not supported");
}
public boolean markSupported() {
return false;
}
private static final int MAX_SKIP_BUFFER_SIZE
= 2048;
}
2 InputStream 具体实现类源码分析
2.1 ByteArrayInputStream —— 字节输入流
核心: buf[] 数组,这个数组即是数据流的 源
buf[] 数组,通过构造函数传入! 字节流操作即是,操作数组的位置 pos。思想很简单基本所有操作都被 synchronized 修饰
public class ByteArrayInputStream extends InputStream {
protected byte buf
[];
protected int pos
;
protected int mark
= 0;
protected int count
;
public synchronized int read() {
return (pos
< count
) ? (buf
[pos
++] & 0xff) : -1;
}
public synchronized int read(byte b
[], int off
, int len
) {...}
public synchronized long skip(long n
) {}
public synchronized int available() {}
public void mark(int readAheadLimit
) {
mark
= pos
;
}
public synchronized void reset() {
pos
= mark
;
}
public void close() throws IOException
{}
public ByteArrayInputStream(byte buf
[]) {
this.buf
= buf
;
this.pos
= 0;
this.count
= buf
.length
;
}
public ByteArrayInputStream(byte buf
[], int offset
, int length
) {
this.buf
= buf
;
this.pos
= offset
;
this.count
= Math
.min(offset
+ length
, buf
.length
);
this.mark
= offset
;
}
}
2.2 FileInputStream —— 文件输入流
核心: file、fileDescriptor
通过构造函数 传入 fileName 或 File 类,内部创建一个 文件链接 核心功能实现方法(本地方法):
read0():获取下一个字节readBytes(byte b[], int off, int len):从偏移量 off 开始,读取 len 个字节,放入 b[] 数组中skip0(long n):跳过 n 个字节available0():还剩多少字节close0():关闭文件流 方法没有被 synchronized 修饰,因为最终调用的是本地方法,本地方法应该加了手段
public class FileInputStream extends InputStream {
private final FileDescriptor fd
;
private final String path
;
private FileChannel channel
= null
;
private final Object closeLock
= new Object();
private volatile boolean closed
= false;
public FileInputStream(String name
) throws FileNotFoundException
{
this(name
!= null
? new File(name
) : null
);
}
public FileInputStream(File file
) throws FileNotFoundException
{...}
public FileInputStream(FileDescriptor fdObj
) {...}
private void open(String name
) throws FileNotFoundException
{
open0(name
);
}
public int read() throws IOException
{
return read0();
}
private native int readBytes(byte b
[], int off
, int len
) throws IOException
;
public int read(byte b
[]) throws IOException
{
return readBytes(b
, 0, b
.length
);
}
public int read(byte b
[], int off
, int len
) throws IOException
{
return readBytes(b
, off
, len
);
}
public long skip(long n
) throws IOException
{
return skip0(n
);
}
public int available() throws IOException
{
return available0();
}
public void close() throws IOException
{
synchronized (closeLock
) {
if (closed
) {
return;
}
closed
= true;
}
if (channel
!= null
) {
channel
.close();
}
fd
.closeAll(new Closeable() {
public void close() throws IOException
{
close0();
}
});
}
public final FileDescriptor
getFD() throws IOException
{...}
public FileChannel
getChannel() {
synchronized (this) {
if (channel
== null
) {
channel
= FileChannelImpl
.open(fd
, path
, true, false, this);
}
return channel
;
}
}
protected void finalize() throws IOException
{
if ((fd
!= null
) && (fd
!= FileDescriptor
.in
)) {
close();
}
}
}
2.3 PipedInputStream —— 管道输入流
管道输入流,必须配合管道输出流 (通过构造函数 传入 一个 管道出入流)核心参数:
buffer[]:输入流的存储位置,只有输出流,才能向此 buffer 中放入字节in:可输入的位置,-1表示输入流没启动,输出流 调用 receive() 方法时给 buffer[] 添加值,并 in++out:可读取的位置,从输入流 执行 read() 方法时,读取 buffer[out], 并out++ 核心方法:
receive():由输出流调用,以此来将字节流传入输入流(buffer[] 数组中)read():有输入流调用,获取输入流的字节
public class PipedInputStream extends InputStream {
protected byte buffer
[];
protected int in
= -1;
protected int out
= 0;
public PipedInputStream(PipedOutputStream src
) throws IOException
{
this(src
, DEFAULT_PIPE_SIZE
);
}
public PipedInputStream(PipedOutputStream src
, int pipeSize
)
throws IOException
{
initPipe(pipeSize
);
connect(src
);
}
public void connect(PipedOutputStream src
) throws IOException
{
src
.connect(this);
}
public synchronized void connect(PipedInputStream snk
) throws IOException
{
if (snk
== null
) {
throw new NullPointerException();
} else if (sink
!= null
|| snk
.connected
) {
throw new IOException("Already connected");
}
sink
= snk
;
snk
.in
= -1;
snk
.out
= 0;
snk
.connected
= true;
}
protected synchronized void receive(int b
) throws IOException
{}
synchronized void receive(byte b
[], int off
, int len
) throws IOException
{}
public synchronized int read() throws IOException
{}
public synchronized int read(byte b
[], int off
, int len
) throws IOException
{}
public void close() throws IOException
{
closedByReader
= true;
synchronized (this) {
in
= -1;
}
}
}
2.4 ObjectInputStream —— Java 反序列化输入流
用于反序列化作用的流,其实相当于 装饰者类,提供反序列化功能
public class ObjectInputStream extends InputStream {
private final BlockDataInputStream bin
;
public ObjectInputStream(InputStream in
) throws IOException
{}
public final Object
readObject() throws IOException
, ClassNotFoundException
{}
public Object
readUnshared() throws IOException
, ClassNotFoundException
{}
public ObjectInputStream
.GetField
readFields() {}
public int read() throws IOException
{}
public int read(byte[] buf
, int off
, int len
) throws IOException
{}
public boolean readBoolean() throws IOException
{}
public byte readByte() throws IOException
{}
public int readUnsignedByte() throws IOException
{}
public char readChar() throws IOException
{}
public short readShort() throws IOException
{}
public int readUnsignedShort() throws IOException
{}
public int readInt() throws IOException
{}
public long readLong() throws IOException
{}
public float readFloat() throws IOException
{}
public double readDouble() throws IOException
{}
public void readFully(byte[] buf
) throws IOException
{}
public void readFully(byte[] buf
, int off
, int len
) throws IOException
{}
public String
readUTF() throws IOException
{}
}
2.4.1 BlockDataInputStream
是 ObjectInputStream 的内部类
具有两种模式的输入流
在“默认”模式下,以与dataoutputstream相同的格式输入数据在“块数据”模式下,输入流以块的形式被缓存。当处于默认模式时,不预先缓冲数据;当处于块数据模式时,立即读取当前数据块的所有数据(并缓冲)。
块模式就相当于给输入流加了一层缓冲区
private class BlockDataInputStream extends InputStream implements DataInput {
private boolean blkmode
= false;
BlockDataInputStream(InputStream in
) {
this.in
= new PeekInputStream(in
);
din
= new DataInputStream(this);
}
int peek() throws IOException
{
if (blkmode
) {
if (pos
== end
) {
refill();
}
return (end
>= 0) ? (buf
[pos
] & 0xFF) : -1;
} else {
return in
.peek();
}
}
private void refill() throws IOException
{...}
public float readFloat() throws IOException
{
if (!blkmode
) {
pos
= 0;
in
.readFully(buf
, 0, 4);
} else if (end
- pos
< 4) {
return din
.readFloat();
}
float v
= Bits
.getFloat(buf
, pos
);
pos
+= 4;
return v
;
}
}
2.4.2 PeekInputStream
是 ObjectInputStream 的内部类
提供了获取字节流但不消耗字节流的功能
提供了统计获取字节数的功能
private static class PeekInputStream extends InputStream {
int peek() throws IOException
{
if (peekb
>= 0) {
return peekb
;
}
peekb
= in
.read();
totalBytesRead
+= peekb
>= 0 ? 1 : 0;
return peekb
;
}
}
2.5 SocketInputStream —— 网络输入流
socket 网络连接使用的 输入流核心方法:
socketRead0(): 本地方法,得到网络输入流字节,读到 -1 时,表示流结束read():内部调用 socketRead0() 方法
class SocketInputStream extends FileInputStream {
SocketInputStream(AbstractPlainSocketImpl impl
) throws IOException
{
super(impl
.getFileDescriptor());
this.impl
= impl
;
socket
= impl
.getSocket();
}
private int socketRead(FileDescriptor fd
,byte b
[], int off
, int len
,int timeout
) {
return socketRead0(fd
, b
, off
, len
, timeout
);
}
public int read(byte b
[]) throws IOException
{
return read(b
, 0, b
.length
);
}
public void close() throws IOException
{
if (closing
)
return;
closing
= true;
if (socket
!= null
) {
if (!socket
.isClosed())
socket
.close();
} else
impl
.close();
closing
= false;
}
}
3 Inputstream 装饰者类源码分析
3.1 BufferedInputStream —— 缓冲输入流
通过构造函数,包装一个 输入流,对这个输入流做缓冲,同时实现 mark 和 reset 的功能核心字段
buf[]:用来缓冲输入流的字节数组count:buf 字节数组能读取到的最大下标pos:目前读取 buf[] 的索引markpos :调用 reset 后,pos 会被设为 markposmarklimit:每次 mark 的时候,设置一个值,超过这值时,mark 就失效了(markpos 设为 -1) 核心方法:
fill():用来填充 buf[],当缓冲不够时read():从缓冲中读取一个字节read1(b,off ,len):从缓冲中的 off 偏移,读 len 字节到 b 字节数组中
public class BufferedInputStream extends FilterInputStream {
protected volatile byte buf
[];
protected int count
;
protected int pos
;
protected int markpos
= -1;
protected int marklimit
;
public BufferedInputStream(InputStream in
, int size
) {
super(in
);
if (size
<= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf
= new byte[size
];
}
public synchronized void mark(int readlimit
) {
marklimit
= readlimit
;
markpos
= pos
;
}
public synchronized void reset() throws IOException
{
getBufIfOpen();
if (markpos
< 0)
throw new IOException("Resetting to invalid mark");
pos
= markpos
;
}
public synchronized int read() throws IOException
{
if (pos
>= count
) {
fill();
if (pos
>= count
)
return -1;
}
return getBufIfOpen()[pos
++] & 0xff;
}
private void fill() throws IOException
{
byte[] buffer
= getBufIfOpen();
if (markpos
< 0)
pos
= 0;
else {
}
count
= pos
;
int n
= getInIfOpen().read(buffer
, pos
, buffer
.length
- pos
);
if (n
> 0)
count
= n
+ pos
;
}
}
3.2 DataInputStream —— 基本类型反序列化输入流
通过构造函数,传入输入流,提供对输入流进行基本类型反序列化功能
完全可以配合 BufferInputStream
核心方法:
readFully(b, off, len):从输入流中读取字节,一直循环读取到 len 字节才返回,如果一直到没有字节了还没读满,则报错readBoolean():读取下一个字节,如果不是 0,则返回 true,否则返回 falsereadLine():此方法不能正确的将字节转为字符,被 BufferedReader 取代 BufferedReader reader
= new BufferedReader(new InputStreamReader(in
));
reader
.readLine();
readUTF():获取下一个 UTF-8 的字符
public final int readInt() throws IOException
{
int ch1
= in
.read();
int ch2
= in
.read();
int ch3
= in
.read();
int ch4
= in
.read();
if ((ch1
| ch2
| ch3
| ch4
) < 0)
throw new EOFException();
return ((ch1
<< 24) + (ch2
<< 16) + (ch3
<< 8) + (ch4
<< 0));
}
public final char readChar() throws IOException
{
int ch1
= in
.read();
int ch2
= in
.read();
if ((ch1
| ch2
) < 0)
throw new EOFException();
return (char)((ch1
<< 8) + (ch2
<< 0));
}
public final byte readByte() throws IOException
{
int ch
= in
.read();
if (ch
< 0)
throw new EOFException();
return (byte)(ch
);
}
3.3 GZIPInputStream —— 读取GZIP 格式输入流
内部原理留待以后分析估计是 readTrailer() 方法起主要作用
public class GZIPInputStream extends InflaterInputStream {
protected CRC32 crc
= new CRC32();
protected boolean eos
;
private boolean closed
= false;
public GZIPInputStream(InputStream in
, int size
) throws IOException
{
super(in
, new Inflater(true), size
);
usesDefaultInflater
= true;
readHeader(in
);
}
public int read(byte[] buf
, int off
, int len
) throws IOException
{
ensureOpen();
if (eos
) {
return -1;
}
int n
= super.read(buf
, off
, len
);
if (n
== -1) {
if (readTrailer())
eos
= true;
else
return this.read(buf
, off
, len
);
} else {
crc
.update(buf
, off
, n
);
}
return n
;
}
}
3.4 ZIPInputStream —— 读取ZIP 格式输入流
内部原理留待以后分析