package java.io;
interface有Closeable、Flushable
abstract class 有InputStream、OutputStream、Reader、Writer
class有InputStreamReader、OutputStreamWriter,FileReader、FileWriter
----------------------------
InputStream是所有字节输入流的父类
package java.io; /** * This abstract class is the superclass of all classes representing * an input stream of bytes. * * <p> Applications that need to define a subclass of <code>InputStream</code> * must always provide a method that returns the next byte of input. * * @author Arthur van Hoff * @see java.io.BufferedInputStream * @see java.io.ByteArrayInputStream * @see java.io.DataInputStream * @see java.io.FilterInputStream * @see java.io.InputStream#read() * @see java.io.OutputStream * @see java.io.PushbackInputStream * @since JDK1.0 */ public abstract class InputStream implements Closeable {
内部有一个抽象函数。read方法会阻塞,除非:1输入数据可获得,2流读完了,3发生io异常。read的返回值是一个0-255的int,表示一个byte
/** * Reads the next byte of data from the input stream. The value byte is * returned as an <code>int</code> in the range <code>0</code> to * <code>255</code>. If no byte is available because the end of the stream * has been reached, the value <code>-1</code> is returned. This method * blocks until input data is available, the end of the stream is detected, * or an exception is thrown. * * <p> A subclass must provide an implementation of this method. * * @return the next byte of data, or <code>-1</code> if the end of the * stream is reached. * @exception IOException if an I/O error occurs. */ public abstract int read() throws IOException;
对应的,OutputStream是字节输出流的父类,有一个write抽象函数。参数int中的低8位会被写入输出流,高24位会被忽略。
/** * Writes the specified byte to this output stream. The general * contract for <code>write</code> is that one byte is written * to the output stream. The byte to be written is the eight * low-order bits of the argument <code>b</code>. The 24 * high-order bits of <code>b</code> are ignored. * <p> * Subclasses of <code>OutputStream</code> must provide an * implementation for this method. * * @param b the <code>byte</code>. * @exception IOException if an I/O error occurs. In particular, * an <code>IOException</code> may be thrown if the * output stream has been closed. */ public abstract void write(int b) throws IOException;
FileInputStream直接继承了InputStream,被设计用来读取二进制字节流文件,例如图片。其中read间接调用了本地函数
/** * A <code>FileInputStream</code> obtains input bytes * from a file in a file system. What files * are available depends on the host environment. * * <p><code>FileInputStream</code> is meant for reading streams of raw bytes * such as image data. For reading streams of characters, consider using * <code>FileReader</code>. * * @author Arthur van Hoff * @see java.io.File * @see java.io.FileDescriptor * @see java.io.FileOutputStream * @see java.nio.file.Files#newInputStream * @since JDK1.0 */ public class FileInputStream extends InputStream -------------------------------------- /** * Reads a byte of data from this input stream. This method blocks * if no input is yet available. * * @return the next byte of data, or <code>-1</code> if the end of the * file is reached. * @exception IOException if an I/O error occurs. */ public int read() throws IOException { return read0(); } private native int read0() throws IOException;
它有三个构造函数public FileInputStream(String)间接调用了public FileInputStream(File)。
public FileInputStream(String name) throws FileNotFoundException { this(name != null ? new File(name) : null); } public FileInputStream(File file) throws FileNotFoundException { String name = (file != null ? file.getPath() : null); SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(name); } if (name == null) { throw new NullPointerException(); } if (file.isInvalid()) { throw new FileNotFoundException("Invalid file path"); } fd = new FileDescriptor(); fd.attach(this); path = name; open(name); } public FileInputStream(FileDescriptor fdObj) { SecurityManager security = System.getSecurityManager(); if (fdObj == null) { throw new NullPointerException(); } if (security != null) { security.checkRead(fdObj); } fd = fdObj; path = null; /* * FileDescriptor is being shared by streams. * Register this stream with FileDescriptor tracker. */ fd.attach(this); }
看一下java.io.File;
首先,类注释明确指出了java.io.File是文件和文件夹的抽象表示,不单单是文件哦!
/** * An abstract representation of file and directory pathnames. * public class File implements Serializable, Comparable<File> {
--------------------------
看字符流吧
BufferedReader是直接继承自Reader的字符流,并且自带缓冲。缓冲区大小可以指定,不指定采用默认值8192
/** * Reads text from a character-input stream, buffering characters so as to * provide for the efficient reading of characters, arrays, and lines. * * <p> The buffer size may be specified, or the default size may be used. The * default is large enough for most purposes. **/ public class BufferedReader extends Reader {
构造函数有两个,BufferedReader(Reader)调用BufferedReader(Reader,int),其中defaultCharBufferSize=8192;
需要注意的是,BufferedReader作为一个Reader,本身需要外部的Reader作为参数,我想到了装饰模式。
BufferedReader是一个Reader但是本身不完整,它本质是对Reader做了装饰。
/** * Creates a buffering character-input stream that uses an input buffer of * the specified size. * * @param in A Reader * @param sz Input-buffer size * * @exception IllegalArgumentException If {@code sz <= 0} */ 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; } /** * Creates a buffering character-input stream that uses a default-sized * input buffer. * * @param in A Reader */ public BufferedReader(Reader in) { this(in, defaultCharBufferSize); }
BufferedInputStream也是一样,不同的是BufferedInputStream继承InputStream,是对字节流的装饰。并且BufferedInputStream提供了对mark和reset的支持。
/** * A <code>BufferedInputStream</code> adds * functionality to another input stream-namely, * the ability to buffer the input and to * support the <code>mark</code> and <code>reset</code> * methods. When the <code>BufferedInputStream</code> * is created, an internal buffer array is * created. As bytes from the stream are read * or skipped, the internal buffer is refilled * as necessary from the contained input stream, * many bytes at a time. The <code>mark</code> * operation remembers a point in the input * stream and the <code>reset</code> operation * causes all the bytes read since the most * recent <code>mark</code> operation to be * reread before new bytes are taken from * the contained input stream. * * @author Arthur van Hoff * @since JDK1.0 */ public class BufferedInputStream extends FilterInputStream {
构造函数如下
/** * Creates a <code>BufferedInputStream</code> * and saves its argument, the input stream * <code>in</code>, for later use. An internal * buffer array is created and stored in <code>buf</code>. * * @param in the underlying input stream. */ public BufferedInputStream(InputStream in) { this(in, DEFAULT_BUFFER_SIZE); } /** * Creates a <code>BufferedInputStream</code> * with the specified buffer size, * and saves its argument, the input stream * <code>in</code>, for later use. An internal * buffer array of length <code>size</code> * is created and stored in <code>buf</code>. * * @param in the underlying input stream. * @param size the buffer size. * @exception IllegalArgumentException if {@code size <= 0}. */ public BufferedInputStream(InputStream in, int size) { super(in); if (size <= 0) { throw new IllegalArgumentException("Buffer size <= 0"); } buf = new byte[size]; }
-----------------------
从字节流到字符流的桥梁
InputStreamReader继承自Reader,它的主要工作是将字节流解码成字符流。
InputStreamReader里面有一个变量StreamDecoder sd,实际工作其实都是有这个sd来做的。说不出来这是什么模式,但不是代理模式。sun.nio.cs.StreamDecoder的源码没有找到。
/** * An InputStreamReader is a bridge from byte streams to character streams: It * reads bytes and decodes them into characters using a specified {@link * java.nio.charset.Charset charset}. The charset that it uses * may be specified by name or may be given explicitly, or the platform's * default charset may be accepted. * * <p> Each invocation of one of an InputStreamReader's read() methods may * cause one or more bytes to be read from the underlying byte-input stream. * To enable the efficient conversion of bytes to characters, more bytes may * be read ahead from the underlying stream than are necessary to satisfy the * current read operation. * * <p> For top efficiency, consider wrapping an InputStreamReader within a * BufferedReader. For example: * * <pre> * BufferedReader in * = new BufferedReader(new InputStreamReader(System.in)); * </pre> * * @see BufferedReader * @see InputStream * @see java.nio.charset.Charset * * @author Mark Reinhold * @since JDK1.1 */ 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); } } /** * Creates an InputStreamReader that uses the named charset. * * @param in * An InputStream * * @param charsetName * The name of a supported * {@link java.nio.charset.Charset charset} * * @exception UnsupportedEncodingException * If the named charset is not supported */ public InputStreamReader(InputStream in, String charsetName) throws UnsupportedEncodingException { super(in); if (charsetName == null) throw new NullPointerException("charsetName"); sd = StreamDecoder.forInputStreamReader(in, this, charsetName); } /** * Creates an InputStreamReader that uses the given charset. * * @param in An InputStream * @param cs A charset * * @since 1.4 * @spec JSR-51 */ public InputStreamReader(InputStream in, Charset cs) { super(in); if (cs == null) throw new NullPointerException("charset"); sd = StreamDecoder.forInputStreamReader(in, this, cs); } /** * Creates an InputStreamReader that uses the given charset decoder. * * @param in An InputStream * @param dec A charset decoder * * @since 1.4 * @spec JSR-51 */ public InputStreamReader(InputStream in, CharsetDecoder dec) { super(in); if (dec == null) throw new NullPointerException("charset decoder"); sd = StreamDecoder.forInputStreamReader(in, this, dec); }
这四个构造函数都是调用了StreamDecoder.forInputStreamReader函数
----------------------------
总结一下,在这几个常用的io流中,本质上说程序员只能从文件构造流,或者使用外部提供的流,例如System.in,socket.getInputStream;
其他的类都是对流的装饰。