Java的Channel通道之FileChannel類詳解
更新時間:2023年10月24日 09:44:56 作者:liyong0829
這篇文章主要介紹了Java的Channel通道之FileChannel類詳解,FileChannel類是Java NIO中的一個重要類,用于在文件中進行讀寫操作,它提供了一種高效的方式來處理大文件和隨機訪問文件的需求,需要的朋友可以參考下
Channel(通道)之FileChannel類
- FileChannel類的基本使用 獲取FileChannel類的對象
- java.nio.channels.FileChannel (抽象類):用于讀、寫文件的通道
- FileChannel是抽象類,我們可以通過FileInputStream和FileOutputStream的getChannel()方法方便的獲取一個它的子類對象。
FileInputStream fi=new FileInputStream(new File(src)); FileOutputStream fo=new FileOutputStream(new File(dst)); //獲得傳輸通道channel FileChannel inChannel=fi.getChannel(); FileChannel outChannel=fo.getChannel();
使用FileChannel類完成文件的復制
public static void main(String[] args) throws Exception{
FileInputStream fis = new FileInputStream("a.txt");
FileOutputStream fos = new FileOutputStream("aCopy1.txt");
// 獲得FileChannel管道對象
FileChannel c1 = fis.getChannel();
FileChannel c2 = fos.getChannel();
// 創(chuàng)建ByteBuffer數(shù)組
ByteBuffer b = ByteBuffer.allocate(1000);
// 循環(huán)讀取數(shù)據(jù)
while ((c1.read(b)) != -1){// 讀取的字節(jié)會填充postion到limit位置之間
// 重置 postion為0,limit為postion的位置
b.flip();
// 寫出數(shù)據(jù)
c2.write(b);// 會把postion到limit之間的數(shù)據(jù)寫出
// 還原
b.clear();// positon為:0 limit為: capacity 用于下次讀取
}
// 釋放資源
c2.close();
c1.close();
fos.close();
fis.close();
/*byte[] bys = new byte[8192];
int len;
while ((len = fis.read(bys)) != -1){
fos.write(bys,0,len);
}
fos.close();
fis.close();*/
}
FileChannel結(jié)合MappedByteBuffer實現(xiàn)高效讀寫
MappedByteBuffer類
- 使用FileChannel結(jié)合ByteBuffer實現(xiàn)的管道讀寫,但并不能提高文件的讀寫效率。
- ByteBuffer有個抽象子類:MappedByteBuffer,它可以將文件直接映射至內(nèi)存,把硬盤中的讀寫變成內(nèi)存中的讀寫, 所以可以提高大文件的讀寫效率
- 可以調(diào)用FileChannel的map()方法獲取一個MappedByteBuffer,map()方法的原型: MappedByteBuffer map(MapMode mode, long position, long size); 說明:將節(jié)點中從position開始的size個字節(jié)映射到返回的MappedByteBuffer中
//復制2GB以下的文件 //map的第三個參數(shù)被限制在Integer.MAX_VALUE(字節(jié)) = 2G
public static void main(String[] args) throws Exception{
//java.io.RandomAccessFile類,可以設置讀、寫模式的IO流類。
//"r"表示:只讀--輸入流,只讀就可以。
RandomAccessFile r1 = new RandomAccessFile("a.txt","r");
//"rw"表示:讀、寫--輸出流,需要讀、寫。
RandomAccessFile r2 = new RandomAccessFile("aCopy2.txt","rw");
// 獲得FileChannel管道對象
FileChannel c1 = r1.getChannel();
FileChannel c2 = r2.getChannel();
// 獲取文件的大小
long size = c1.size();
// 直接把硬盤中的文件映射到內(nèi)存中
MappedByteBuffer b1 = c1.map(FileChannel.MapMode.READ_ONLY, 0, size);
MappedByteBuffer b2 = c2.map(FileChannel.MapMode.READ_WRITE, 0, size);
// 循環(huán)讀取數(shù)據(jù)
for (long i = 0; i < size; i++) {
// 讀取字節(jié)
byte b = b1.get();
// 保存到第二個數(shù)組中
b2.put(b);
}
// 釋放資源
c2.close();
c1.close();
r2.close();
r1.close();
}
//下例使用循環(huán),將文件分塊,可以高效的復制大于2G的文件
public static void main(String[] args) throws Exception{
//java.io.RandomAccessFile類,可以設置讀、寫模式的IO流類。
//"r"表示:只讀--輸入流,只讀就可以。
RandomAccessFile r1 = new RandomAccessFile("H:\\資料.zip","r");
//"rw"表示:讀、寫--輸出流,需要讀、寫。
RandomAccessFile r2 = new RandomAccessFile("H:\\資料2.zip","rw");
// 獲得FileChannel管道對象
FileChannel c1 = r1.getChannel();
FileChannel c2 = r2.getChannel();
// 獲取文件的大小
long size = c1.size();
// 每次期望復制500M
int everySize = 1024*1024*500;
// 總共需要復制多少次
long count = size % everySize == 0 ? size/everySize : size/everySize+1;
// 開始復制
for (long i = 0; i < count; i++) {
// 每次開始復制的位置
long start = everySize*i;
// 每次復制的實際大小
long trueSize = size - start > everySize ? everySize : size - start;
// 直接把硬盤中的文件映射到內(nèi)存中
MappedByteBuffer b1 = c1.map(FileChannel.MapMode.READ_ONLY, start, trueSize);
MappedByteBuffer b2 = c2.map(FileChannel.MapMode.READ_WRITE, start, trueSize);
// 循環(huán)讀取數(shù)據(jù)
for (long j = 0; j < trueSize; j++) {
// 讀取字節(jié)
byte b = b1.get();
// 保存到第二個數(shù)組中
b2.put(b);
}
}
// 釋放資源
c2.close();
c1.close();
r2.close();
r1.close();
}
ServerSocketChannel和SocketChannel創(chuàng)建連接
SocketChannel創(chuàng)建連接
- 客戶端:SocketChannel類用于連接的客戶端,它相當于:Socket。
ServerSocketChanne創(chuàng)建連接
- 服務器端:ServerSocketChannel類用于連接的服務器端,它相當于:ServerSocket 服務器代碼
public class Server {
public static void main(String[] args) throws IOException{
//創(chuàng)建對象
//ServerSocket ss = new ServerSocket(8888);
//創(chuàng)建
ServerSocketChannel ssc = ServerSocketChannel.open();
//服務器綁定端口
ssc.bind(new InetSocketAddress(8888));
//連接上客戶端
SocketChannel sc = ssc.accept();
//服務器端接受數(shù)據(jù)
//創(chuàng)建數(shù)組
ByteBuffer buffer = ByteBuffer.allocate(1024);
//接收數(shù)據(jù)
int len = sc.read(buffer);
//打印結(jié)構
System.out.println(new String(buffer.array(),0,len));
//關閉資源
sc.close();
}
}
客戶端代碼
public class Client {
public static void main(String[] args) {
//創(chuàng)建對象
//Socket s = new Socket("127.0.0.1",8888);
//創(chuàng)建對象
SocketChannel sc = SocketChannel.open();
//連接服務器
sc.connect(new InetSocketAddress("127.0.0.1",8888));
//客戶端發(fā)數(shù)據(jù)
//創(chuàng)建數(shù)組
ByteBuffer buffer = ByteBuffer.allocate(1024);
//數(shù)組中添加數(shù)據(jù)
buffer.put("你好".getBytes());
//切換
buffer.flip();
//發(fā)出數(shù)據(jù)
sc.write(buffer);
//關流
sc.close();
}
}
到此這篇關于Java的Channel通道之FileChannel類詳解的文章就介紹到這了,更多相關Java的FileChannel類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Spring-AOP 靜態(tài)正則表達式方法如何匹配切面
這篇文章主要介紹了Spring-AOP 靜態(tài)正則表達式方法如何匹配切面的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
解決SpringBoot集成Eureka導致返回結(jié)果由json變?yōu)閤ml的問題
這篇文章主要介紹了解決SpringBoot集成Eureka導致返回結(jié)果由json變?yōu)閤ml的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07

