从JDK1.4 开始,Java提供了一些列改进IO新特性,放在Java.nio及其子包下。并改进了原包中的很多类以NIO为基础进行了改写,满足了NIO的功能。
NIO采用内存映射文件的方式来处理输入/输出,将文件或者文件的一段区域映射到内存中,就可以像访问内存一样访问文件,所以速度要比旧IO快很多。
Channel(通道)和 Buffer(缓冲)是NIO的两个核心对象。
Channel是NIO中输入、输出通道,所有数据都需要通过channel传输。Channel和旧的InputStream、OutputStream的区别在于他提供了一个map方法,通过该map可以将一块数据映射到内存中。
Buffer是唯一能和Channel直接交互的缓冲器,也就是我们其实只是和缓冲器交互,通过缓冲器和Channel交互。
除了boolean,其他基本类型都有相应的Buffer类:ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer。。。
Buffer的基本使用方法:
import java.nio.*;
public class BufferTest
{
public static void main(String[] args)
{
//创建Buffer
CharBuffer buff = CharBuffer.allocate(8); //1
System.out.println("capacity: "
+ buff.capacity());
System.out.println("limit: "
+ buff.limit());
System.out.println("position: "
+ buff.position());
//放入元素
buff.put('a'); //2
buff.put('b'); //3
buff.put('c'); //4
System.out.println("加入三个元素后,position = "
+ buff.position());//postion =3
//调用flip()方法,为读取数据做准备
buff.flip(); //5
System.out.println("执行flip()后,limit = "
+ buff.limit());//limit=3
System.out.println("position = "
+ buff.position());//postion=0
//取出第一个元素
System.out.println("第一个元素(position=0):"
+ buff.get()); // a
System.out.println("取出一个元素后,position = "
+ buff.position());//postion=1
//调用clear方法,为写数据做准备
buff.clear(); //7
System.out.println("执行clear()后,limit = "
+ buff.limit());//limit=8
System.out.println("执行clear()后,position = "
+ buff.position());//postion=0
System.out.println("执行clear()后,缓冲区内容并没有被清除:"
+ buff.get(2)); //b
System.out.println("执行绝对读取后,position = "
+ buff.position());//postion=0
}
}
Channel可以直接将指定文件的部分或全部映射成Buffer
程序不能直接访问Channel中的数据,必须通过Buffer访问。
FileChannel读写文件
mport java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
public class FileChannelTest
{
public static void main(String[] args)
{
FileChannel inChannel = null;
FileChannel outChannel = null;
try
{
File f = new File("FileChannelTest.java");
//创建FileInputStream,以该文件输入流创建FileChannel
inChannel = new FileInputStream(f)
.getChannel();
//将FileChannel里的全部数据映射成ByteBuffer
MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY,
0 , f.length());
//使用GBK的字符集来创建解码器
Charset charset = Charset.forName("GBK");
//以文件输出流创建FileBuffer,用以控制输出
outChannel = new FileOutputStream("a.txt")
.getChannel();
//直接将buffer里的数据全部输出
outChannel.write(buffer);
//再次调用buffer的clear()方法,复原limit、position的位置
buffer.clear();
//创建解码器(CharsetDecoder)对象
CharsetDecoder decoder = charset.newDecoder();
//使用解码器将ByteBuffer转换成CharBuffer
CharBuffer charBuffer = decoder.decode(buffer);
//CharBuffer的toString方法可以获取对应的字符串
System.out.println(charBuffer);
}
catch (IOException ex)
{
ex.printStackTrace();
}
finally
{
try
{
if (inChannel != null)
inChannel.close();
if (outChannel != null)
outChannel.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
}
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
public class FileChannelTest
{
public static void main(String[] args)
{
FileChannel inChannel = null;
FileChannel outChannel = null;
try
{
File f = new File("FileChannelTest.java");
//创建FileInputStream,以该文件输入流创建FileChannel
inChannel = new FileInputStream(f)
.getChannel();
//将FileChannel里的全部数据映射成ByteBuffer
MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY,
0 , f.length());
//使用GBK的字符集来创建解码器
Charset charset = Charset.forName("GBK");
//以文件输出流创建FileBuffer,用以控制输出
outChannel = new FileOutputStream("a.txt")
.getChannel();
//直接将buffer里的数据全部输出
outChannel.write(buffer);
//再次调用buffer的clear()方法,复原limit、position的位置
buffer.clear();
//创建解码器(CharsetDecoder)对象
CharsetDecoder decoder = charset.newDecoder();
//使用解码器将ByteBuffer转换成CharBuffer
CharBuffer charBuffer = decoder.decode(buffer);
//CharBuffer的toString方法可以获取对应的字符串
System.out.println(charBuffer);
}
catch (IOException ex)
{
ex.printStackTrace();
}
finally
{
try
{
if (inChannel != null)
inChannel.close();
if (outChannel != null)
outChannel.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
}
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
public class ReadFile
{
public static void main(String[] args)
{
FileChannel fcin = null;
try
{
//创建文件输入流
FileInputStream fis = new FileInputStream("ReadFile.java");
//创建一个FileChannel
fcin = fis.getChannel();
//定义一个ByteBuffer对象,用于重复取水
ByteBuffer bbuff = ByteBuffer.allocate(1024);
//将FileChannel中数据放入ByteBuffer中
while( fcin.read(bbuff) != -1 )
{
//锁定Buffer的空白区
bbuff.flip();
//创建Charset对象
Charset charset = Charset.forName("gb2312");
//创建解码器(CharsetDecoder)对象
CharsetDecoder decoder = charset.newDecoder();
//将ByteBuffer的内容转码
CharBuffer cbuff = decoder.decode(bbuff);
System.out.println(cbuff);
//将Buffer初始化,为下一次取数据做准备
bbuff.clear();
}
}
catch (IOException ex)
{
ex.printStackTrace();
}
finally
{
try
{
if (fcin != null)
fcin.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
}
Java提供了Charset来处理字节序列和字符序列(字符串)之间的转换关系
import java.nio.charset.*;
import java.nio.*;
public class CharsetTransform
{
public static void main(String[] args)
throws Exception
{
//创建简体中文对应的Charset
Charset cn = Charset.forName("GBK");
//获取cn对象对应的编码器和解码器
CharsetEncoder cnEncoder = cn.newEncoder();
CharsetDecoder cnDecoder = cn.newDecoder();
//创建一个CharBuffer对象
CharBuffer cbuff = CharBuffer.allocate(8);
cbuff.put('孙');
cbuff.put('悟');
cbuff.put('空');
cbuff.flip();
//将CharBuffer中的字符序列转换成字节序列
ByteBuffer bbuff = cnEncoder.encode(cbuff);
//循环访问ByteBuffer中的每个字节
for (int i = 0; i < bbuff.capacity() ; i++)
{
System.out.print(bbuff.get(i) + " ");
}
//将ByteBuffer的数据解码成字符序列
System.out.println("\n"
+ cnDecoder.decode(bbuff));
}
}
Java提供了FileLock来支持文件锁定功能
import java.nio.*;
import java.nio.channels.*;
import java.io.*;
public class FileLockTest
{
public static void main(String[] args)
{
FileChannel channel = null;
try
{
//使用FileOutputStream获取FileChannel
channel = new FileOutputStream("a.txt")
.getChannel();
//使用非阻塞式方式对指定文件加锁
FileLock lock = channel.tryLock();
//程序暂停5s
Thread.sleep(5000);
//释放锁
lock.release();
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
try
{
if (channel != null)
channel.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
}