• Java io包 FileInputStream&FileOutStream


    分析FileInputStream,其中finalize()被覆写,优先使用finalize(),close()方法可能内存泄漏,或者手动colse()之前做好检查

    package java.io;

    import java.nio.channels.FileChannel;

    import sun.nio.ch.FileChannelImpl;

    /**

     * 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

    {

        /* File Descriptor - handle to the open file */

        private final FileDescriptor fd;

        /**

         * 文件路径

         *(如果传入FileDescriptor实例化输入流则其为null)

         */

        private final String path;

       

        /**

         * 读、写、操作文件的通道

         */

        private FileChannel channel = null;

        /**

         * 锁,给close()加锁

         */

        private final Object closeLock = new Object();

       

        /**

         * 锁的条件值

         */

        private volatile boolean closed = false;

       

        /**

         * 检查name是否为null,不是调用另外一个构造函数,传入 new File(name)

         * @param name

         * @throws FileNotFoundException

         */

        public FileInputStream(String name) throws FileNotFoundException {

            this(name != null ? new File(name) : null);

        }

        /**

         * 1、为name赋值

         * 2、安全检查

         * 3、判断文件是否存在

         * 4、创建一个文件描述类

         * 5、绑定其到this

         * 6、打开文件(native方法)

         * @param file

         * @throws FileNotFoundException

         */

        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);

        }

        /**

         * 不推荐采用该构造方法

         * 引用自jdk:文件描述符类的实例用作表示打开文件,开放套接字或其他字节源或信宿的底层机器特定结构的不透明句柄。 文件描述符的主要实际用途是创建一个FileInputStream或FileOutputStream来包含它。 应用程序不应创建自己的文件描述符。

         * @param fdObj

         */

        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);

        }

        /**

         * native方法,打开文件

         * @param name

         * @throws FileNotFoundException

         */

        private native void open0(String name) throws FileNotFoundException;

        /**

         * 打开文件

         * @param name

         * @throws FileNotFoundException

         */

        private void open(String name) throws FileNotFoundException {

            open0(name);

        }

        /**

         * 读取字节

         * @return

         * @throws IOException

         */

        public int read() throws IOException {

            return read0();

        }

       

        /**

         * native方法、读取字节

         * @return

         * @throws IOException

         */

        private native int read0() throws IOException;

        /**

         * native方法,读取字节数组

         * @param b

         * @param off

         * @param len

         * @return

         * @throws IOException

         */

        private native int readBytes(byte b[], int off, int len) throws IOException;

        /**

         * 读取字节数组

         * @param b

         * @return

         * @throws IOException

         */

        public int read(byte b[]) throws IOException {

            return readBytes(b, 0, b.length);

        }

        /**

         * 读取字节

         * @param b

         * @param off

         * @param len

         * @return

         * @throws IOException

         */

        public int read(byte b[], int off, int len) throws IOException {

            return readBytes(b, off, len);

        }

        /**

         * 跳过n个字节

         * @param n

         * @return

         * @throws IOException

         */

        public long skip(long n) throws IOException {

            return skip0(n);

        }

        private native long skip0(long n) throws IOException;

        /**

         * 可读取最大字节数

         * @return

         * @throws IOException

         */

        public int available() throws IOException {

            return available0();

        }

        private native int available0() throws IOException;

        /**

         * 关闭输入流

         * @throws IOException

         */

        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();

               }

            });

        }

        /**

         * 获取文件描述类

         * @return

         * @throws IOException

         */

        public final FileDescriptor getFD() throws IOException {

            if (fd != null) {

                return fd;

            }

            throw new IOException();

        }

        /**

         * 获取文件描述通道

         * @return

         */

        public FileChannel getChannel() {

            synchronized (this) {

                if (channel == null) {

                    channel = FileChannelImpl.open(fd, path, true, false, this);

                }

                return channel;

            }

        }

        private static native void initIDs();

        private native void close0() throws IOException;

        static {

            initIDs();

        }

        /**

         *确保输入流不持有其他对象的引用,再关闭输入流

         * @throws IOException

         */

        protected void finalize() throws IOException {

            if ((fd != null) &&  (fd != FileDescriptor.in)) {

                /* if fd is shared, the references in FileDescriptor

                 * will ensure that finalizer is only called when

                 * safe to do so. All references using the fd have

                 * become unreachable. We can call close()

                 */

                close();

            }

        }

    }

    分析FileOutputStream,和FileInputStream类似,多了一个append属性,表示追加和覆写两种模式

    package java.io;

    import java.nio.channels.FileChannel;

    import sun.nio.ch.FileChannelImpl;

    /**

     * A file output stream is an output stream for writing data to a

     * <code>File</code> or to a <code>FileDescriptor</code>. Whether or not

     * a file is available or may be created depends upon the underlying

     * platform.  Some platforms, in particular, allow a file to be opened

     * for writing by only one <tt>FileOutputStream</tt> (or other

     * file-writing object) at a time.  In such situations the constructors in

     * this class will fail if the file involved is already open.

     *

     * <p><code>FileOutputStream</code> is meant for writing streams of raw bytes

     * such as image data. For writing streams of characters, consider using

     * <code>FileWriter</code>.

     *

     * @author  Arthur van Hoff

     * @see     java.io.File

     * @see     java.io.FileDescriptor

     * @see     java.io.FileInputStream

     * @see     java.nio.file.Files#newOutputStream

     * @since   JDK1.0

     */

    public

    class FileOutputStream extends OutputStream

    {

        /**

         * The system dependent file descriptor.

         */

        private final FileDescriptor fd;

        /**

         * True if the file is opened for append.

         */

        private final boolean append;

        /**

         * The associated channel, initialized lazily.

         */

        private FileChannel channel;

        /**

         * The path of the referenced file

         * (null if the stream is created with a file descriptor)

         */

        private final String path;

        private final Object closeLock = new Object();

        private volatile boolean closed = false;

        /**

         * Creates a file output stream to write to the file with the

         * specified name. A new <code>FileDescriptor</code> object is

         * created to represent this file connection.

         * <p>

         * First, if there is a security manager, its <code>checkWrite</code>

         * method is called with <code>name</code> as its argument.

         * <p>

         * If the file exists but is a directory rather than a regular file, does

         * not exist but cannot be created, or cannot be opened for any other

         * reason then a <code>FileNotFoundException</code> is thrown.

         *

         * @param      name   the system-dependent filename

         * @exception  FileNotFoundException  if the file exists but is a directory

         *                   rather than a regular file, does not exist but cannot

         *                   be created, or cannot be opened for any other reason

         * @exception  SecurityException  if a security manager exists and its

         *               <code>checkWrite</code> method denies write access

         *               to the file.

         * @see        java.lang.SecurityManager#checkWrite(java.lang.String)

         */

        public FileOutputStream(String name) throws FileNotFoundException {

            this(name != null ? new File(name) : null, false);

        }

        /**

         * Creates a file output stream to write to the file with the specified

         * name.  If the second argument is <code>true</code>, then

         * bytes will be written to the end of the file rather than the beginning.

         * A new <code>FileDescriptor</code> object is created to represent this

         * file connection.

         * <p>

         * First, if there is a security manager, its <code>checkWrite</code>

         * method is called with <code>name</code> as its argument.

         * <p>

         * If the file exists but is a directory rather than a regular file, does

         * not exist but cannot be created, or cannot be opened for any other

         * reason then a <code>FileNotFoundException</code> is thrown.

         *

         * @param     name        the system-dependent file name

         * @param     append      if <code>true</code>, then bytes will be written

         *                   to the end of the file rather than the beginning

         * @exception  FileNotFoundException  if the file exists but is a directory

         *                   rather than a regular file, does not exist but cannot

         *                   be created, or cannot be opened for any other reason.

         * @exception  SecurityException  if a security manager exists and its

         *               <code>checkWrite</code> method denies write access

         *               to the file.

         * @see        java.lang.SecurityManager#checkWrite(java.lang.String)

         * @since     JDK1.1

         */

        public FileOutputStream(String name, boolean append)

            throws FileNotFoundException

        {

            this(name != null ? new File(name) : null, append);

        }

        /**

         * Creates a file output stream to write to the file represented by

         * the specified <code>File</code> object. A new

         * <code>FileDescriptor</code> object is created to represent this

         * file connection.

         * <p>

         * First, if there is a security manager, its <code>checkWrite</code>

         * method is called with the path represented by the <code>file</code>

         * argument as its argument.

         * <p>

         * If the file exists but is a directory rather than a regular file, does

         * not exist but cannot be created, or cannot be opened for any other

         * reason then a <code>FileNotFoundException</code> is thrown.

         *

         * @param      file               the file to be opened for writing.

         * @exception  FileNotFoundException  if the file exists but is a directory

         *                   rather than a regular file, does not exist but cannot

         *                   be created, or cannot be opened for any other reason

         * @exception  SecurityException  if a security manager exists and its

         *               <code>checkWrite</code> method denies write access

         *               to the file.

         * @see        java.io.File#getPath()

         * @see        java.lang.SecurityException

         * @see        java.lang.SecurityManager#checkWrite(java.lang.String)

         */

        public FileOutputStream(File file) throws FileNotFoundException {

            this(file, false);

        }

        /**

         * Creates a file output stream to write to the file represented by

         * the specified <code>File</code> object. If the second argument is

         * <code>true</code>, then bytes will be written to the end of the file

         * rather than the beginning. A new <code>FileDescriptor</code> object is

         * created to represent this file connection.

         * <p>

         * First, if there is a security manager, its <code>checkWrite</code>

         * method is called with the path represented by the <code>file</code>

         * argument as its argument.

         * <p>

         * If the file exists but is a directory rather than a regular file, does

         * not exist but cannot be created, or cannot be opened for any other

         * reason then a <code>FileNotFoundException</code> is thrown.

         *

         * @param      file               the file to be opened for writing.

         * @param     append      if <code>true</code>, then bytes will be written

         *                   to the end of the file rather than the beginning

         * @exception  FileNotFoundException  if the file exists but is a directory

         *                   rather than a regular file, does not exist but cannot

         *                   be created, or cannot be opened for any other reason

         * @exception  SecurityException  if a security manager exists and its

         *               <code>checkWrite</code> method denies write access

         *               to the file.

         * @see        java.io.File#getPath()

         * @see        java.lang.SecurityException

         * @see        java.lang.SecurityManager#checkWrite(java.lang.String)

         * @since 1.4

         */

        public FileOutputStream(File file, boolean append)

            throws FileNotFoundException

        {

            String name = (file != null ? file.getPath() : null);

            SecurityManager security = System.getSecurityManager();

            if (security != null) {

                security.checkWrite(name);

            }

            if (name == null) {

                throw new NullPointerException();

            }

            if (file.isInvalid()) {

                throw new FileNotFoundException("Invalid file path");

            }

            this.fd = new FileDescriptor();

            fd.attach(this);

            this.append = append;

            this.path = name;

            open(name, append);

        }

        /**

         * Creates a file output stream to write to the specified file

         * descriptor, which represents an existing connection to an actual

         * file in the file system.

         * <p>

         * First, if there is a security manager, its <code>checkWrite</code>

         * method is called with the file descriptor <code>fdObj</code>

         * argument as its argument.

         * <p>

         * If <code>fdObj</code> is null then a <code>NullPointerException</code>

         * is thrown.

         * <p>

         * This constructor does not throw an exception if <code>fdObj</code>

         * is {@link java.io.FileDescriptor#valid() invalid}.

         * However, if the methods are invoked on the resulting stream to attempt

         * I/O on the stream, an <code>IOException</code> is thrown.

         *

         * @param      fdObj   the file descriptor to be opened for writing

         * @exception  SecurityException  if a security manager exists and its

         *               <code>checkWrite</code> method denies

         *               write access to the file descriptor

         * @see        java.lang.SecurityManager#checkWrite(java.io.FileDescriptor)

         */

        public FileOutputStream(FileDescriptor fdObj) {

            SecurityManager security = System.getSecurityManager();

            if (fdObj == null) {

                throw new NullPointerException();

            }

            if (security != null) {

                security.checkWrite(fdObj);

            }

            this.fd = fdObj;

            this.append = false;

            this.path = null;

            fd.attach(this);

        }

        /**

         * Opens a file, with the specified name, for overwriting or appending.

         * @param name name of file to be opened

         * @param append whether the file is to be opened in append mode

         */

        private native void open0(String name, boolean append)

            throws FileNotFoundException;

        // wrap native call to allow instrumentation

        /**

         * Opens a file, with the specified name, for overwriting or appending.

         * @param name name of file to be opened

         * @param append whether the file is to be opened in append mode

         */

        private void open(String name, boolean append)

            throws FileNotFoundException {

            open0(name, append);

        }

        /**

         * Writes the specified byte to this file output stream.

         *

         * @param   b   the byte to be written.

         * @param   append   {@code true} if the write operation first

         *     advances the position to the end of file

         */

        private native void write(int b, boolean append) throws IOException;

        /**

         * Writes the specified byte to this file output stream. Implements

         * the <code>write</code> method of <code>OutputStream</code>.

         *

         * @param      b   the byte to be written.

         * @exception  IOException  if an I/O error occurs.

         */

        public void write(int b) throws IOException {

            write(b, append);

        }

        /**

         * Writes a sub array as a sequence of bytes.

         * @param b the data to be written

         * @param off the start offset in the data

         * @param len the number of bytes that are written

         * @param append {@code true} to first advance the position to the

         *     end of file

         * @exception IOException If an I/O error has occurred.

         */

        private native void writeBytes(byte b[], int off, int len, boolean append)

            throws IOException;

        /**

         * Writes <code>b.length</code> bytes from the specified byte array

         * to this file output stream.

         *

         * @param      b   the data.

         * @exception  IOException  if an I/O error occurs.

         */

        public void write(byte b[]) throws IOException {

            writeBytes(b, 0, b.length, append);

        }

        /**

         * Writes <code>len</code> bytes from the specified byte array

         * starting at offset <code>off</code> to this file output stream.

         *

         * @param      b     the data.

         * @param      off   the start offset in the data.

         * @param      len   the number of bytes to write.

         * @exception  IOException  if an I/O error occurs.

         */

        public void write(byte b[], int off, int len) throws IOException {

            writeBytes(b, off, len, append);

        }

        /**

         * Closes this file output stream and releases any system resources

         * associated with this stream. This file output stream may no longer

         * be used for writing bytes.

         *

         * <p> If this stream has an associated channel then the channel is closed

         * as well.

         *

         * @exception  IOException  if an I/O error occurs.

         *

         * @revised 1.4

         * @spec JSR-51

         */

        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();

               }

            });

        }

        /**

         * Returns the file descriptor associated with this stream.

         *

         * @return  the <code>FileDescriptor</code> object that represents

         *          the connection to the file in the file system being used

         *          by this <code>FileOutputStream</code> object.

         *

         * @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 output stream.

         *

         * <p> The initial {@link java.nio.channels.FileChannel#position()

         * position} of the returned channel will be equal to the

         * number of bytes written to the file so far unless this stream is in

         * append mode, in which case it will be equal to the size of the file.

         * Writing bytes to this stream will increment the channel's position

         * accordingly.  Changing the channel's position, either explicitly or by

         * writing, will change this stream's file position.

         *

         * @return  the file channel associated with this file output stream

         *

         * @since 1.4

         * @spec JSR-51

         */

        public FileChannel getChannel() {

            synchronized (this) {

                if (channel == null) {

                    channel = FileChannelImpl.open(fd, path, false, true, append, this);

                }

                return channel;

            }

        }

        /**

         * Cleans up the connection to the file, and ensures that the

         * <code>close</code> method of this file output stream is

         * called when there are no more references to this stream.

         *

         * @exception  IOException  if an I/O error occurs.

         * @see        java.io.FileInputStream#close()

         */

        protected void finalize() throws IOException {

            if (fd != null) {

                if (fd == FileDescriptor.out || fd == FileDescriptor.err) {

                    flush();

                } else {

                    /* if fd is shared, the references in FileDescriptor

                     * will ensure that finalizer is only called when

                     * safe to do so. All references using the fd have

                     * become unreachable. We can call close()

                     */

                    close();

                }

            }

        }

        private native void close0() throws IOException;

        private static native void initIDs();

        static {

            initIDs();

        }

    }

  • 相关阅读:
    第三章 系统总线
    人工神经网络及其应用
    专家系统
    遗传算法
    搜索算法策略
    js判断有无属性及新添属性
    vue 文件插件 Vetur 设置说明官网
    vue 获得当前无素并做相应处理
    VUE style 绑定
    vue入门基础知识点测试
  • 原文地址:https://www.cnblogs.com/shineyoung/p/11375314.html
Copyright © 2020-2023  润新知