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



發佈了71 篇原創文章 · 獲贊 2 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章