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

Java -- 新IO -- 目录-LMLPHPJava -- 新IO -- 目录-LMLPHP

    啦啦啦

05-08 08:46