国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

Java NIO(四)--FileChannel

2019-11-06 06:11:23
字體:
來源:轉載
供稿:網友

一、概述

NIO 中FileChannel可以理解為一個連接到文件的通道,可以通過FileChannel對文件進行讀寫; FileChannel沒有非阻塞模式,讀寫都只有阻塞的方式;

二、操作

打開FileChannel 

在使用FileChannel之前,必須先打開它。但是,我們無法直接打開一個FileChannel,需要通過使用一個InputStream、OutputStream或RandomaccessFile來獲取一個FileChannel實例。下面是通過RandomAccessFile打開FileChannel的示例: 

RandomAccessFile fromFile = new RandomAccessFile("D:/fromFile.txt", "rw");//獲取channelFileChannel fromChannel = fromFile.getChannel();

從FileChannel讀取數據 

首先,分配一個Buffer。從FileChannel中讀取的數據將被讀到Buffer中。 然后,調用FileChannel.read()方法。該方法將數據從FileChannel讀取到Buffer中。read()方法返回的int值表示了有多少字節被讀到了Buffer中。如果返回-1,表示到了文件末尾。如:
ByteBuffer buf = ByteBuffer.allocate(1024*4);  int bytesRead = inChannel.read(buf);  

向FileChannel寫數據 

使用FileChannel.write()方法向FileChannel寫數據,該方法的參數是一個Buffer。如:
String newData = "New String to write to file..." + System.currentTimeMillis();    ByteBuffer buf = ByteBuffer.allocate(1024*4);  buf.clear();  buf.put(newData.getBytes());    buf.flip();    while(buf.hasRemaining()) {      channel.write(buf);  }  注意FileChannel.write()是在while循環中調用的。因為無法保證write()方法一次能向FileChannel寫入多少字節,因此需要重復調用write()方法,直到Buffer中已經沒有尚未寫入通道的字節。 

關閉FileChannel 

用完FileChannel后必須將其關閉。如: 
channel.close();  

FileChannel的position方法 

有時可能需要在FileChannel的某個特定位置進行數據的讀/寫操作。可以通過調用position()方法獲取FileChannel的當前位置。 也可以通過調用position(long pos)方法設置FileChannel的當前位置。 這里有兩個例子: 
long pos = channel.position();  channel.position(pos +123);  如果將位置設置在文件結束符之后,然后試圖從文件通道中讀取數據,讀方法將返回-1 —— 文件結束標志。 如果將位置設置在文件結束符之后,然后向通道中寫數據,文件將撐大到當前位置并寫入數據。這可能導致“文件空洞”,磁盤上物理文件中寫入的數據間有空隙。 

FileChannel的size方法 

FileChannel實例的size()方法將返回該實例所關聯文件的大小。如: 
long fileSize = channel.size();  

FileChannel的truncate方法 

可以使用FileChannel.truncate()方法截取一個文件。截取文件時,文件將中指定長度后面的部分將被刪除。如:
channel.truncate(1024);  這個例子截取文件的前1024個字節。 

FileChannel的force方法 

FileChannel.force()方法將通道里尚未寫入磁盤的數據強制寫到磁盤上。出于性能方面的考慮,操作系統會將數據緩存在內存中,所以無法保證寫入到FileChannel里的數據一定會即時寫到磁盤上。要保證這一點,需要調用force()方法。 force()方法有一個boolean類型的參數,指明是否同時將文件元數據(權限信息等)寫到磁盤上。 下面的例子同時將文件數據和元數據強制寫到磁盤上: 
channel.force(true);  

示例

對于資源文件,操作完都是需要關閉的;以下是一個完成讀寫實例代碼:
public static void main(String[] args) throws IOException {	RandomAccessFile fromFile = new RandomAccessFile("src//a.txt", "rw");	RandomAccessFile toFile = new RandomAccessFile("src//b.txt", "rw");	// 獲取channel	FileChannel fromChannel = fromFile.getChannel();	FileChannel toChannel = toFile.getChannel();	// 定義緩沖大小	int bufSize = 1024 * 4;	// 定義緩沖	ByteBuffer byteBuffer = ByteBuffer.allocate(bufSize);	int len = 0;	// 將數據從源channel寫入到緩沖區	while ((len = fromChannel.read(byteBuffer)) != -1) {		// 切換到讀模式		byteBuffer.flip();		while (byteBuffer.hasRemaining()) {			// 讀取緩沖區數據寫到目標channel			toChannel.write(byteBuffer);		}		// 清空緩沖		byteBuffer.clear();	}	// 釋放資源	toChannel.close();	fromChannel.close();	toFile.close();	fromFile.close();}緩沖區的hasRemainning方法返回一個boolean,標識緩沖區中是否還有數據沒有讀取,寫入FileChannel必須在一個循環中,因為write方法無法保證緩沖區的數據一次全部寫入;

通過FileChannel直接傳輸

在兩個通道間傳輸數據,如果其中有一個是FileChannel,可以不使用緩沖區讀出、寫入的方式進行傳輸,可以使用FileChannel的transferFrom 和 transferTo 方法;

1. transferFrom

public long transferFrom(ReadableByteChannel src, long position, long count) throws IOException; 該方法可以從其他通道直接將數據傳輸到fileChannel,position參數表示從position開始先目標文件寫入數據,count參表示最多寫入的數據量,但是不一定會寫入這個參數的數據量,如果來源通道沒有那么多可讀數據的話;該方法返回一個long值表示成功寫入通道的數據量;

2. transferTo

public abstract long transferTo(long position, long count, WritableByteChannel target) throws IOException; 改方法與transferFrom相反,是將FileChannel的數據直接寫入到目標通道,position參數表示從position位置開始讀取數據寫入,count參數表示要寫入數據的大小,但是不一定寫入這個參數的數據量,如果這個fileChannel沒有那么多數據可以讀取的話;該方法返回一個long值,表示實際寫入目標通道的數據量;以下是一個通過transferFrom/transferTo方法復制文件的實例代碼:
public static void main(String[] args) throws IOException {        RandomAccessFile fromFile = new RandomAccessFile("src//a.txt", "rw");        RandomAccessFile inFile = new RandomAccessFile("src//a.txt", "rw");        FileChannel fromChannel = fromFile.getChannel();        FileChannel inChannel = inFile.getChannel();        int position = 0;        long count = fromChannel.size();        long successCount = inChannel.transferFrom(fromChannel, position, count);        //long successCount = fromChannel.transferTo(position, count, inChannel);        System.out.PRintln(successCount);    }

文件鎖定

FileChannel的鎖,與一般的對象鎖相似,都是勸告式鎖;獲取鎖后,它不阻止任何形式的數據訪問,而是與對象鎖相似,程序中可以通過它進行多線程間協調(線程安全處理);

通過FileChannel的lock方法,可以鎖定整個文件或指定一部分;         請求獲取的鎖有兩種:共享鎖和排它鎖;共享鎖可以獲取多個,而排它鎖只能獲取到一個;由于不同的操作系統對文件系統鎖的實現方式不一樣,有些實現了共享鎖,而另外一些只實現了排它鎖;

以下是一個獲取文件鎖的實例代碼,可以通過同時運行多個觀察效果:

public static void main(String[] args) throws Exception {        RandomAccessFile fromFile = new RandomAccessFile("src//a.txt", "rw");        FileChannel fromChannel = fromFile.getChannel();        System.out.println("trying to lock file...");        int start = 0;        int end = 10;        FileLock fileLock = fromChannel.lock(start, end, false);        System.out.println("after lock");        System.out.println("pause...");        Thread.sleep(8000);        System.out.println("releasing file lock");        fileLock.release();        System.out.println("after release.");        fromChannel.close();        fromFile.close();    }lock 方法中,start、end參數指定鎖定文件的部分,第三個boolean參數,true:表示獲取共享鎖,false:表示獲取排它鎖; 還有一個lock()無參的方法,實際是調用:

public final FileLock lock() throws IOException {        return lock(0L, Long.MAX_VALUE, false);}由于不是全部操作系統都支持共享鎖,所以就算請求獲取共享鎖,但是也可能會返回一個排它鎖,可以通過isShare方法確定鎖類型:
fileLock.isShared();對此,我們不如直接只使用排它鎖,而不是進行isShare邏輯的判斷。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 麻阳| 神木县| 张家界市| 和田市| 曲麻莱县| 黄梅县| 新巴尔虎右旗| 屏东县| 修武县| 连南| 图片| 辽宁省| 油尖旺区| 屯留县| 汾阳市| 宁海县| 天柱县| 昂仁县| 兴义市| 青冈县| 友谊县| 大城县| 永胜县| 广昌县| 阿克苏市| 台山市| 车险| 婺源县| 汝州市| 伊通| 泾阳县| 静宁县| 福海县| 虎林市| 屏东县| 沅陵县| 平乡县| 商水县| 陆河县| 墨脱县| 区。|