【给JDK IO源码加点注释】02 FileInputStream、FileOutputStream

package java.io;

import java.nio.channels.FileChannel;
import sun.nio.ch.FileChannelImpl;


/**
*FileInputStream是一个从文件获取字节流的类
* @since   1.0
*/
public
class FileInputStream extends InputStream
{
    /* 文件描述符用于表示一个打开的文件*/
    private final FileDescriptor fd;

    /**文件的路径
     */
    private final String path;
      
    private volatile FileChannel channel;
  //用于同步操作的锁
    private final Object closeLock = new Object();
  //流是否关闭标志
    private volatile boolean closed;

    /**
     * 使用文件的绝对路径或者相对路径名创建文件输入流
     * @param      文件路径
     * @exception  FileNotFoundException 如果文件不存在t ,传入的是一个目录名以及因为其他原因不能打开文件。                
     * @exception  SecurityException     没有读取权限
     */
    public FileInputStream(String name) throws FileNotFoundException {
        //调用下面一个构造方法
        this(name != null ? new File(name) : null);
    }

    /**
     *通过file对象创建输入流
     *
     * @param      file  需要读取的file对象。
     * @exception  FileNotFoundException  如果文件不存在t ,传入的是一个目录名以及因为其他原因不能打开文件。   
     * @exception  SecurityException     没有读取权限
     * @see        java.io.File#getPath()
     * @see        java.lang.SecurityManager#checkRead(java.lang.String)
     */
    public FileInputStream(File file) throws FileNotFoundException {
        String name = (file != null ? file.getPath() : null);
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
      //检查是否有读取权限,没有则抛出SecurityException
            security.checkRead(name);
        }
        if (name == null) {
            throw new NullPointerException();
        }
        //判断文件路径是否有效(其实是判断路径中是否有空格,不代表文件存在)
        if (file.isInvalid()) {
            throw new FileNotFoundException("Invalid file path");
        }
        //初始化一个FileDescriptor用于描述文件连接
        fd = new FileDescriptor();
        //将this注册到fd对象中。
        fd.attach(this);
        path = name;
        open(name);
    }

    /**
     * 通过FileDescriptor(代表一个已经存在的文件连接)来创建流
   *通过同一个fd创建的流在其中一个关闭时全部都会关闭。
     * @param      fdObj   filedescriptor对象(可通过getFD()获取)
     * @throws     SecurityException      文件不可读
     * @see        SecurityManager#checkRead(java.io.FileDescriptor)
     */
    public FileInputStream(FileDescriptor fdObj) {
        SecurityManager security = System.getSecurityManager();
        if (fdObj == null) {
            throw new NullPointerException();
        }
        if (security != null) {
            security.checkRead(fdObj);
        }
        fd = fdObj;
        path = null;

      //将this注册到fd对象中。
        fd.attach(this);
    }

    /**
     *读取一个字节
     */
    public int read() throws IOException {
        return read0();
    }


    /**
     *参考InputStream
     */
    public int read(byte b[]) throws IOException {
        return readBytes(b, 0, b.length);
    }

    /**
     *参考InputStream
     */
    public int read(byte b[], int off, int len) throws IOException {
        return readBytes(b, off, len);
    }

    /**
     * 跳过制定字节数
     * @param      n  需要跳过的字节数是
     * @return     实际跳过的字节数。
     * @exception  IOException 
     */
    public long skip(long n) throws IOException {
        return skip0(n);
    }


    /**
     *
     * @return    返回一个估计的可读字节数
     * @exception  IOException 
     */
    public int available() throws IOException {
        return available0();
    }


    /**
     *关闭当前流并释放与当前流关联的系统资源
     *
     * @exception  IOException  if an I/O error occurs.
     *
     * @revised 1.4
     * @spec JSR-51
     */
    public void close() throws IOException {
        //判断流是否已经关闭,已关闭直接返回。
        if (closed) {
            return;
        }
        //获取锁
        synchronized (closeLock) {
            //双重检测机制,防止多次关闭流。
            if (closed) {
                return;
            }
            closed = true;
        }

        FileChannel fc = channel;
        if (fc != null) {
            // possible race with getChannel(), benign since
            // FileChannel.close is final and idempotent
            fc.close();
        }
    //调用fd的closeAll方法,此方法会关闭所有注册到此fd对象中的流。
    /**例如
    *FileInputStream in = new FileInputStream("src\\test.txt");    
    *FileInputStream in2 = new FileInputStream(in.getFD());
    *in.close();
    *in2.read();
    *这段代码会抛出IOException:Stream Closed
    */
        fd.closeAll(new Closeable() {
            public void close() throws IOException {
               close0();
           }
        });
    }

    /**
     * 返回fd对象即当前的文件连接
     * @return     与当前流关联的fd对象
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.FileDescriptor
     */
    public final FileDescriptor getFD() throws IOException {
        if (fd != null) {
            return fd;
        }
        throw new IOException();
    }

    /**
     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
     * object associated with this file input stream.
     *
     * <p> The initial {@link java.nio.channels.FileChannel#position()
     * position} of the returned channel will be equal to the
     * number of bytes read from the file so far.  Reading bytes from this
     * stream will increment the channel's position.  Changing the channel's
     * position, either explicitly or by reading, will change this stream's
     * file position.
     *
     * @return  the file channel associated with this file input stream
     *
     * @since 1.4
     * @spec JSR-51
     */
    public FileChannel getChannel() {
        FileChannel fc = this.channel;
        if (fc == null) {
            synchronized (this) {
                fc = this.channel;
                if (fc == null) {
                    this.channel = fc = FileChannelImpl.open(fd, path, true, false, this);
                    if (closed) {
                        try {
                            // possible race with close(), benign since
                            // FileChannel.close is final and idempotent
                            fc.close();
                        } catch (IOException ioe) {
                            throw new InternalError(ioe); // should not happen
                        }
                    }
                }
            }
        }
        return fc;
    }  
}
FileOutputStream与FileInputStream基本相同
只是多了个构造方法  public FileOutputStream(String name, boolean append)来创建在文件末尾追加内容的输出流(默认是不追加,会导致文件原本内容被清除)。
posted @ 2018-07-01 23:40  Panic1  阅读(75)  评论(0)    收藏  举报