zoukankan      html  css  js  c++  java
  • java文件系统中的的NIO与IO

    java从jdk1.4后就引入了java NIO机制:

         NIO的显著特点就是通道(channel)、缓冲(buffer)、选择器(selector),NIO机制中添加了传统I/O机制中没有的非阻塞调用(这对于网络通信很有用,可以有效利用CPU),但是这个只能对于网络通道(Socketchannel)才适用,filechannel还是阻塞调用。

         我们现在专门分析的是java中的文件I/O机制,而不管网络的socket通信机制。

         Java中传统的文件系统I/O机制是Filesystem和File,java中的Filesystem是java中的内部类,不提供对外的显示特性,File类中的包含了Filesystem的对象,从而对于File的操作,比如rename、create etc 都转成成java中的内部类Filesystem的操作。下面的是java中的Filesystem的抽象类:

         abstract class FileSystem {

        /**
         * Return the FileSystem object representing this platform's local
         * filesystem.
         */
        public static native FileSystem getFileSystem();


        /* -- Normalization and construction -- */

        /**
         * Return the local filesystem's name-separator character.
         */
        public abstract char getSeparator();

        /**
         * Return the local filesystem's path-separator character.
         */
        public abstract char getPathSeparator();
      
       。。。。。。

    }

       每个操作系统中都有一个具体的文件系统,而在windows下,通过Filesystem的getFilesystem()操作获取本地文件系统,win32Filesystem; 而对于linux系统下,获取的是unixFilesystem;

       而java中传统的I/O机制中的File对象,通过包含Filesystem对象,来达到对于文件系统下文件的管理操作create、delete、rename等。而关于文件的I/O数据流,输入和输出,采用的是Fileinputstream和Fileoutputstream。下面以Fileinputstream为例,Fileinputstream中的文件操作函数包括如下:

        private native void open(String name) throws FileNotFoundException;

            /**
         * 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 {
            Object traceContext = IoTrace.fileReadBegin(path);
            int b = 0;
            try {
                b = read0();
            } finally {
                IoTrace.fileReadEnd(traceContext, b == -1 ? 0 : 1);
            }
            return b;
        }

        private native int read0() throws IOException;

            /**
         * Reads a subarray 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
         * @exception IOException If an I/O error has occurred.
         */
        private native int readBytes(byte b[], int off, int len) throws IOException;
     
         public native long skip(long n) throws IOException;

       等,上面是几个重要的函数,每次File读取操作的时候都有个文件读取位置,在linux文件系统下是文件描述符FileDescriptor,而windows系统下是handler,读取位置是通过FileDescriptor或者Handler来完成的,每次只能从上一次的位置读取文件操作。

       但是Java中的NIO(New I/O)中引入了FileChannel,在FileChannel中有如下新特性:

    1. 字节读取可以以相对位置读取,也可以以绝对位置读取
    2. 一个文件的区域可以直接映射进入到内存中去
    3. 字节可以从一个文件传送到另外一个文件,通过transferto方法,直接在内核空间进行文件传输,而不用在用户态和内核态之间来回切换,有效减少了文件传输时间(在linux下有个相应的函数是sendfile,直接是在内核态进行文件传输,而无须在用户态和内核态之间来回进行数据切换)

        相应的Filechannel是一个抽象类:

        public  abstract class FileChannel
        extends AbstractInterruptibleChannel
        implements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel {。。。}
      

       新增加的方法是:
           /**
         * Reads a sequence of bytes from this channel into the given buffer,
         * starting at the given file position.
         *
         * <p> This method works in the same manner as the {@link
         * #read(ByteBuffer)} method, except that bytes are read starting at the
         * given file position rather than at the channel's current position.  This
         * method does not modify this channel's position.  If the given position
         * is greater than the file's current size then no bytes are read.  </p>
         public abstract int read(ByteBuffer dst, long position) throws IOException;
       /**
         * Writes a sequence of bytes to this channel from the given buffer,
         * starting at the given file position.
         *
         * <p> This method works in the same manner as the {@link
         * #write(ByteBuffer)} method, except that bytes are written starting at
         * the given file position rather than at the channel's current position.
         * This method does not modify this channel's position.  If the given
         * position is greater than the file's current size then the file will be
         * grown to accommodate the new bytes; the values of any bytes between the
         * previous end-of-file and the newly-written bytes are unspecified.  </p>
         public abstract int write(ByteBuffer src, long position) throws IOException;
      /**
         * Acquires a lock on the given region of this channel's file.
          public abstract FileLock lock(long position, long size, boolean shared)
            throws IOException;
       /**
         * Forces any updates to this channel's file to be written to the storage
         * device that contains it.
       public abstract void force(boolean metaData) throws IOException;
      /**
         * Transfers bytes from this channel's file to the given writable byte
         * channel.
         * <p> This method is potentially much more efficient than a simple loop
         * that reads from this channel and writes to the target channel.  Many
         * operating systems can transfer bytes directly from the filesystem cache
         * to the target channel without actually copying them.  </p>
        public abstract long transferTo(long position, long count,
                                        WritableByteChannel target)
            throws IOException;
       上述是FileChannel新增的方法。

       传统的Java中的I/O机制中的FileInputStream的成员变量:

           private final FileDescriptor fd;
       即传统的java文件系统采用的是通过文件描述符的形式来记住文件的存取位置

       而java中的NIO机制也是采用类似的机制:

          // Used to make native read and write calls
        private static NativeDispatcher nd;

        // Memory allocation size for mapping buffers
        private static long allocationGranularity;

        // Cached field for MappedByteBuffer.isAMappedBuffer
        private static Field isAMappedBufferField;

        // File descriptor
        private FileDescriptor fd;
       上面是一个具体的Filechannel类,FilechannelImpl部分成员变量。

     

        

      

  • 相关阅读:
    Oracel System.Data.OracleClient requires Oracle client software version 8.1.7 or greater错误的解决方法
    oracle中CASE 的用法(摘录)
    ajaxpro 的一些用法,是在vs.net2003上
    我所知道的web下的打印方法
    电容触摸技术实用教程
    BLE资料应用笔记 持续更新
    蓝牙BLE实用教程
    README
    android 应用笔记
    Git 教程
  • 原文地址:https://www.cnblogs.com/linghuchong0605/p/3995103.html
Copyright © 2011-2022 走看看