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部分成员变量。

时间: 2024-08-25 16:42:19

java文件系统中的的NIO与IO的相关文章

Java的中BIO、NIO、AIO-2

Java的中BIO.NIO.AIO-2 java 举个栗子 接上一篇接着说,C/S模式.Reactor模式.Proactor模式是服务器处理IO常用的处理模型,这一篇就来解释一下这几种模式: 以一个餐饮为例,每一个人来就餐就是一个事件,他会先看一下菜单,然后点餐.就像一个网站会有很多的请求,要求服务器做一些事情.处理这些就餐事件的就需要我们的服务人员了. 在多线程处理的方式会是这样的: 一个人来就餐,一个服务员去服务,然后客人会看菜单,点菜. 服务员将菜单给后厨. 二个人来就餐,二个服务员去服务

Java的中BIO、NIO、AIO-1

Java的中BIO.NIO.AIO-1 java 最近在项目中用到TCP通信来完成命令和运行结果的交互,用的是典型的TCP通信中的C/S架构,原因很简单:在业务需求低的环境下,这种架构简单.稳定还容易写.但是在实际部署的情况下,一直出现读不到数据的空指针异常,按说BIO模式开发的应该阻塞直到有数据读取,没有找到原因就变通写了一个消息队列,使用定时器每1s从定时器中拿数据,解决了这个问题.但是想想这种同步阻塞的形式,就想了解一下其他的模式:NIO.AIO.好了,啰嗦了好多,进入正题: IO操作的基

初理解Java中的BIO,NIO,AIO

初识: java 中的 BIO.NIO和 AIO 理解为是 Java 语言对操作系统的各种 IO 模型的封装.程序员在使用这些 API 的时候,不需要关心操作系统层面的知识,也不需要根据不同操作系统编写不同的代码.只需要使用Java的API就可以了. 在讲 BIO,NIO,AIO 之前先来回顾一下这样几个概念:同步与异步,阻塞与非阻塞. 同步与异步: 同步: 同步就是发起一个调用后,被调用者未处理完请求之前,调用不返回. 异步: 异步就是发起一个调用后,立刻得到被调用者的回应表示已接收到请求,但

Java Project打包,发布到Web Project下之后,运行Web Project出现找不到Java Project中资源的解决办法

要想使得web项目可以访问引用的Java Project中的资源,需要在Java Project中,将需要的IO操作的文件都放置到src目录下 法一 在Java Project中,有IO操作的类需要这样写 package cn.edu.test; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.Inp

Java中的NIO和IO的对比分析

总的来说,java中的IO和NIO主要有三点区别: IO                  NIO 面向流     面向缓冲 阻塞IO  非阻塞IO  无   选择器(Selectors) 1.面向流与面向缓冲 Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的. Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方.此外,它不能前后移动流中的数据.如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区. Java

Java 7 中 NIO.2 的使用——第四节 文件和目录

Files类提供了很多方法用于检查在于你真正实际去操作一个文件或目录.这些方法强烈推荐,也非常有用,也能避免很多异常的发生.例如,一个很好的习惯就是在你试着移动一个文件从一个地方到另一个地方的时候,先检查文件是否存在. 检查一个文件或目录是否存在 在前面的例子中已经演示到,Path实例能够有效的映射到一个文件或是目录甚至这个文件或目录物理上根本不存在.再是,Path的很多方法不会实际操作文件本身就能成功地应用.所以,事先判断一个目录或是文件存在就显得非常重要.下面有两个方法用来判断文件是否存在.

Java 7 中 NIO.2 的使用——第一节 Path 类的使用

路径隶属于文件系统,实际上它是存储和组织媒体文件的格式,通常在一块或多块硬盘设备上,以便于非常容易地检索.文件系统可以通过  java.nio.file.FileSystems 这个final 类来访问,通常我们用来获取它的实例然后做我们想做的事情.FileSystems 包含下面两个非常重要的方法,还有 newFileSystem() 方法,用来构建一个新的文件系统实例. getDefault(): 这个静态方法会返回一个默认的FileSystem 给 JVM——通常是操作系统默认的文件系统.

[转载] Java NIO与IO

原文地址:http://tutorials.jenkov.com/java-nio/nio-vs-io.html 作者:Jakob Jenkov   译者:郭蕾    校对:方腾飞 当学习了Java NIO和IO的API后,一个问题马上涌入脑海: 我应该何时使用IO,何时使用NIO呢?在本文中,我会尽量清晰地解析Java NIO和IO的差异.它们的使用场景,以及它们如何影响您的代码设计. Java NIO和IO的主要区别 下表总结了Java NIO和IO之间的主要差别,我会更详细地描述表中每部分

java 的nio与io对比

转:本文并非Java.io或Java.nio的使用手册,也不是如何使用Java.io与Java.nio的技术文档.这里只是尝试比较这两个包,用最简单的方式突出它们的区别和各自的特性.Java.nio提出了新的流(stream)通讯概念并且加入了新的缓冲.文件流以及socket(套接字)特性. java.io 概览 这个包通过数据流和序列化机制来实现系统输入和输出.并且支持多种类型的数据流,包括简单的字节.原生数据类型.地区字符以及对象.流是一个数据的序列:一个程序使用输入流从一个源头读取数据: