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