首页 > 技术文章 > Java -- 新IO -- 目录

ClassNotFoundException 2017-06-11 16:42 原文

    20.1 Java 新IO简介

    20.2 缓冲区与Buffer

      例:演示缓冲区的操作流程

      Class : IntBufferDemo01

      20.2.2 深入缓冲区操作

      20.2.3 创建子缓冲区

      20.2.4 创建只读缓冲区

      20.2.5 创建直接缓冲区

    20.3 通道

      20.3.1 FileChannel

        例:使用输出通道输出内容

        Class : FileChannelDemo01

package lime.pri.limeNio._20_3_1.channeldemo;

import java.io.File;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class FileChannelDemo01 {
    public static void main(String[] args) throws Exception {
        String info[] = {"lime","oracle","Lime","Oracle"};
        File file = new File("F:/channels/out.txt");
        FileOutputStream output = null;
        output = new FileOutputStream(file);
        FileChannel fout = null;
        fout = output.getChannel();
        ByteBuffer buf = ByteBuffer.allocate(1024);
        for(int i = 0;i < info.length;i++){
            buf.put(info[i].getBytes());
            buf.put("\n".getBytes());
        }
        buf.flip();
        fout.write(buf);
        fout.close();
        output.close();
    }
}

        例:使用通道进行读写操作

        Class :FileChannelDemo02

package lime.pri.limeNio._20_3_1.channeldemo;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class FileChannelDemo02 {

    public static void main(String[] args) throws Exception {
        File file1 = new File("F:/channels/note.txt");
        File file2 = new File("F:/channels/outnote.txt");
        FileInputStream input = null;
        FileOutputStream output = null;
        input = new FileInputStream(file1);
        output = new FileOutputStream(file2);
        FileChannel fin = null;
        FileChannel fout = null;
        fin = input.getChannel();
        fout = output.getChannel();
        ByteBuffer buf = ByteBuffer.allocate(1024);
        int temp = 0;
        while((temp = fin.read(buf)) != -1){
            buf.flip();
            fout.write(buf);
            buf.clear();
        }
        fin.close();
        fout.close();
        input.close();
        output.close();
    }
}

      20.3.2 内存映射

        内存映射可以把文件映射到内存中,这样文件内的数据就可以用内存读/写指令来访问,而不是用InputStream或OutputStream这样的I/O操作类,采用此种方式读取文件的速度是最快的。

        提示:Java中访问文件内容的4中方法。

          ⊙ RandomAccessFile,随机读取数据,此种访问速度较慢。

          ⊙ FileInputStream,文件输入流,使用此种方式数度较慢。

          ⊙ 缓冲读取(例BufferedReader),使用此种方式访问速度较快。

          ⊙ 内存映射(MappedByteBuffer),使用此种方式读取速度最快。

        例:内存映射

        Class : FileChannelDemo03

package lime.pri.limeNio._20_3_2.channeldemo;

import java.io.File;
import java.io.FileInputStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class FileChannelDemo03 {

    public static void main(String[] args) throws Exception {
        File file = new File("F:/channels/mappedByteBuffer.txt");
        FileInputStream input = null;
        input = new FileInputStream(file);
        FileChannel fin = null;
        fin = input.getChannel();
        MappedByteBuffer mbb = null;
        mbb = fin.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
        byte data[] = new byte[(int)file.length()];
        int foot = 0;
        while(mbb.hasRemaining()){
            data[foot++] = mbb.get();
        }
        System.out.println(new String(data));
        fin.close();
        input.close();
    }
}

    20.4 文件锁:FileLock

      在Java新IO中提供了文件锁的功能,这样当一个线程将文件锁定之后,其他线程是无法操作此文件的。要想进行文件的锁定操作,则要使用FileLock类完成,此类的对象需要依靠FileChannel进行实例化操作。

      ⊙ 共享锁:允许多个线程进行文件的读取操作。

      ⊙ 独占锁:只允许一个线程进行文件的读/写操作。 

      例:将文件锁定

      Class : FileLockDemo

package lime.pri.limeNio._20_4.channeldemo;

import java.io.File;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;

public class FileLockDemo {

    public static void main(String[] args) throws Exception {
        File file = new File("F:/channels/fileLock.txt");
        FileOutputStream output = null;
        output = new FileOutputStream(file,true);
        FileChannel fout = null;
        fout = output.getChannel();
        FileLock lock = fout.tryLock();
        if(lock != null){
            System.out.println(file.getName() + " 文件锁定300秒");
            Thread.sleep(300000);
            lock.release();
            System.out.println(file.getName() + " 文件解除锁定");
        }
        fout.close();
        output.close();
    }
}

    20.5 字符集:Charset

      例:取得Charset类的全部编码

      Class : GetAllCharsetDemo

package lime.pri.limeNio._20_5.channeldemo;

import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;

public class GetAllCharsetDemo {

    public static void main(String[] args) {
        SortedMap<String, Charset> all = null;
        all = Charset.availableCharsets();
        Iterator<Map.Entry<String,Charset>> iter = null;
        iter = all.entrySet().iterator();
        while(iter.hasNext()){
            Map.Entry<String, Charset> me = iter.next();
            System.out.println(me.getKey() + " --> " + me.getValue());
        }
    }
}

      例:编码-解码操作

      Class : CharsetEnDeDemo

    20.6 Selector

      在新IO中Selector是一个极其重要的概念,在原来使用IO和Socket构造网络服务时,所有的网络服务经使用阻塞方式进行客户端的连接,而如果使用了新IO则可以构造一个非阻塞的的网络服务。

      Selector类的常用方法:

        ⊙ public static Selector open() throws IOException :  打开一个选择器。

        ⊙ public abstract int select() throws IOException : 选择一组键,其相应的通道已为 I/O 操作准备就绪。

        ⊙ public abstract Set<SelectionKey> selectedKeys() : 返回此选择器的已选择键集。

      在进行非阻塞网络开发时需要使用SelectableChannel类向Select类注册,而且在新IO中实现网络程序需要依靠ServerSocketChannel类与SocketChannel类,这两个类都是SelectableChannel的子类,SelectableChannel提供了注册Selector的方法和阻塞模式。

      ServerSocketChannel类的常用方法:

        ⊙ public final SelectableChannel configureBlocking(boolean block) throws IOException : 调整此通道的阻塞模式。true:阻塞模式;false:非阻塞模式

        ⊙ public final SelectionKey register(Selector sel, int ops) throws ClosedChannelException :  向给定的选择器注册此通道,返回一个选择键。

        ⊙ public static ServerSocketChannel open() throws IOException : 打开服务器的套接字通道。

        ⊙ public abstract ServerSocket socket() : 返回与此通道关联的服务器套接字。

      在使用register()方法时需要指定一个选择器(Selector对象)以及Select域,Selector对象可以通过Selector中的open()方法取得,而Selector域则在SelectionKey类中定义。

      4中Selector域:

        ⊙ public static final int OP_ACCEPT   = 1 << 4: 相当于ServerSocket中的accpet()操作。

        ⊙ public static final int OP_CONNECT  = 1 << 3 :连接操作。 

        ⊙ public static final int OP_READ = 1 << 0 : 读操作。

        ⊙ public static final int OP_WRITE = 1 << 2 : 写操作。

      如果要使用服务器想客户端发送信息,则需要通过SelectionKey类中提供的方法判断服务器的操作状态。而要想取得客户端的连接也需要使用SelectionKey类。

      SelectionKey常用的方法:

        ⊙ public abstract SelectableChannel channel() : 返回为之创建此键的通道。

        ⊙ public final boolean isAcceptable() : 测试此键的通道是否已准备好接受新的套接字连接。

        ⊙ public final boolean isConnectable() : 测试此键的通道是否已完成其套接字连接操作。

        ⊙ public final boolean isReadable() : 测试此键的通道是否已准备好进行读取。

        ⊙ public final boolean isWritable() : 测试此键的通道是否已准备好进行写入。

      例:取得时间的服务器

      Class : DateServer

package lime.pri.limeNio._20_6.channeldemo.selector;

import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;

public class DateServer {

    public static void main(String[] args) throws Exception {
        int ports[] = {8000,8001,8002,8003,8005,8006};    //定义一组连接端口号
        Selector selector = Selector.open();    //打开一个选择器
        for(int i = 0;i < ports.length;i++){    //构造服务器的启动信息
            ServerSocketChannel initSer = null;    //声明ServerSocketChannel
            initSer = ServerSocketChannel.open();    //打开服务器套接字通道
            initSer.configureBlocking(false);    //服务器配置为非阻塞
            ServerSocket initSock = initSer.socket();    //检索此通道关联的服务器套接字
            InetSocketAddress address = null;    //表示监听地址
            address = new InetSocketAddress(ports[i]);    //实例化绑定地址
            initSock.bind(address);    //绑定地址
            //注册选择器,相当于使用accept()方法接收
            initSer.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("服务器运行,在 " + ports[i] + " 端口监听。");
        }
        int keysAdd = 0;    //接收一组SelectionKey
        while((keysAdd = selector.select()) > 0){    //选择一组键,相应的通道已为IO准备就绪
            Set<SelectionKey> selectedkeys = selector.selectedKeys();    //取出全部生成的key
            Iterator<SelectionKey> iter = selectedkeys.iterator();    //实例化Iterator
            while(iter.hasNext()){    //迭代全部的key
                SelectionKey key = (SelectionKey)iter.next();    //取出每一个SelectionKey
                if(key.isAcceptable()){    //判断客户端是否已经连接上
                    ServerSocketChannel server = (ServerSocketChannel)key.channel();    //取得Channel
                    SocketChannel client = server.accept();    // 接收新连接
                    client.configureBlocking(false);    //设置成非阻塞状态
                    ByteBuffer outBuf = ByteBuffer.allocateDirect(1024);    //开辟缓冲区
                    outBuf.put(("当前时间为:" + new Date()).getBytes());    //缓冲区设置内容
                    outBuf.flip();    //重置缓冲区
                    client.write(outBuf);    //输出信息
                    client.close();    //关闭输出流
                }
            }
            selectedkeys.clear();    //清除全部key
        }
    }
}

      Console : telnet 

 

 

    啦啦啦

推荐阅读