Java 笔记:NIO新IO

java 新 IO

从JDK1.4 开始,Java提供了一些列改进IO新特性,放在Java.nio及其子包下。并改进了原包中的很多类以NIO为基础进行了改写,满足了NIO的功能。


NIO采用内存映射文件的方式来处理输入/输出,将文件或者文件的一段区域映射到内存中,就可以像访问内存一样访问文件,所以速度要比旧IO快很多。


Channel 和 Buffer

Channel(通道)和 Buffer(缓冲)是NIO的两个核心对象。

Channel是NIO中输入、输出通道,所有数据都需要通过channel传输。Channel和旧的InputStream、OutputStream的区别在于他提供了一个map方法,通过该map可以将一块数据映射到内存中。

Buffer是唯一能和Channel直接交互的缓冲器,也就是我们其实只是和缓冲器交互,通过缓冲器和Channel交互


Buffer使用

除了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使用

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();
			}
		}
	}
}

RandomAccessFile追加文件

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();
			}
		}
	}
}

使用固定大小的buffer分多次读写文件

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();
			}
		}
	}
}

Charset 使用

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();
			}
		}
	}
}



你可能感兴趣的:(java)