NIO入门系列之第3章:从理论到实践:NIO 中的读和写
3.1 ?概述
讀和寫是 I/O 的基本過程。從一個通道中讀取很簡單:只需創(chuàng)建一個緩沖區(qū),然后讓通道將數(shù)據(jù)讀到這個緩沖區(qū)中。寫入也相當簡單:創(chuàng)建一個緩沖區(qū),用數(shù)據(jù)填充它,然后讓通道用這些數(shù)據(jù)來執(zhí)行寫入操作。
在本節(jié)中,我們將學習有關在Java 程序中讀取和寫入數(shù)據(jù)的一些知識。我們將回顧 NIO 的主要組件(緩沖區(qū)、通道和一些相關的方法),看看它們是如何交互以進行讀寫的。在接下來的幾節(jié)中,我們將更詳細地分析這其中的每個組件以及其交互。
3.2 ?從文件中讀取
在我們第一個練習中,我們將從一個文件中讀取一些數(shù)據(jù)。如果使用原來的 I/O,那么我們只需創(chuàng)建一個FileInputStream 并從它那里讀取。而在 NIO中,情況稍有不同:我們首先從FileInputStream 獲取一個FileInputStream 對象,然后使用這個通道來讀取數(shù)據(jù)。
在 NIO 系統(tǒng)中,任何時候執(zhí)行一個讀操作,您都是從通道中讀取,但是您不是直接從通道讀取。因為所有數(shù)據(jù)最終都駐留在緩沖區(qū)中,所以您是從通道讀到緩沖區(qū)中。
因此讀取文件涉及三個步驟:(1)從FileInputStream 獲取 Channel,(2) 創(chuàng)建 Buffer,(3) 將數(shù)據(jù)從 Channel 讀到 Buffer 中。
現(xiàn)在,讓我們看一下這個過程。
3.3 ?三個容易的步驟
第一步是獲取通道。我們從 FileInputStream 獲取通道:
FileInputStream fin = new FileInputStream( "readandshow.txt" ); FileChannel fc = fin.getChannel();下一步是創(chuàng)建緩沖區(qū):
ByteBuffer buffer = ByteBuffer.allocate( 1024 );最后,需要將數(shù)據(jù)從通道讀到緩沖區(qū)中,如下所示:
fc.read( buffer );
您會注意到,我們不需要告訴通道要讀多少數(shù)據(jù)到緩沖區(qū)中。每一個緩沖區(qū)都有復雜的內(nèi)部統(tǒng)計機制,它會跟蹤已經(jīng)讀了多少數(shù)據(jù)以及還有多少空間可以容納更多的數(shù)據(jù)。我們將在緩沖區(qū)內(nèi)部細節(jié)中介紹更多關于緩沖區(qū)統(tǒng)計機制的內(nèi)容。
// ReadAndShow package com.mzsx.nio; import java.io.*; import java.nio.*; import java.nio.channels.*; public class ReadAndShow {static public void main(String args[]) throws Exception {//創(chuàng)建FileInputStream實例FileInputStream fin = new FileInputStream("C:\\Users\\Qiang\\Desktop\\hydra.txt");//獲取通道FileChannel fc = fin.getChannel();//創(chuàng)建緩沖區(qū)ByteBuffer buffer = ByteBuffer.allocate(1024);//將數(shù)據(jù)從通道讀到緩沖區(qū)中fc.read(buffer);//反轉(zhuǎn)buffer.flip();int i = 0;while (buffer.remaining() > 0) {byte b = buffer.get();System.out.println("Character " + i + ": " + ((char) b)+" , buffer.remaining():"+buffer.remaining());i++;}fin.close();} }
3.4 ?寫入文件
在 NIO 中寫入文件類似于從文件中讀取。首先從 FileOutputStream 獲取一個通道:
FileOutputStream fout = new FileOutputStream( "writesomebytes.txt" ); FileChannel fc = fout.getChannel();
下一步是創(chuàng)建一個緩沖區(qū)并在其中放入一些數(shù)據(jù)- 在這里,數(shù)據(jù)將從一個名為message 的數(shù)組中取出,這個數(shù)組包含字符串"Some bytes" 的 ASCII 字節(jié)(本教程后面將會解釋buffer.flip() 和 buffer.put() 調(diào)用)。
ByteBuffer buffer = ByteBuffer.allocate( 1024 ); for (int i=0; i<message.length; ++i) {buffer.put( message[i] ); } buffer.flip();
最后一步是寫入緩沖區(qū)中:
fc.write( buffer );注意在這里同樣不需要告訴通道要寫入多數(shù)據(jù)。緩沖區(qū)的內(nèi)部統(tǒng)計機制會跟蹤它包含多少數(shù)據(jù)以及還有多少數(shù)據(jù)要寫入。
// WriteSomeBytes package com.mzsx.nio; import java.io.*; import java.nio.*; import java.nio.channels.*; public class WriteSomeBytes {static private final byte message[] = { 83, 111, 109, 101, 32, 98, 121,116, 101, 115, 46 };static public void main(String args[]) throws Exception {//實例化FileOutputStreamFileOutputStream fout = new FileOutputStream("C:\\Users\\Qiang\\Desktop\\writesomebytes.txt");//獲取通道FileChannel fc = fout.getChannel();//獲取緩沖區(qū)ByteBuffer buffer = ByteBuffer.allocate(1024);//向緩沖區(qū)添加數(shù)據(jù)for (int i = 0; i < message.length; ++i) {buffer.put(message[i]);}buffer.flip();//寫入緩沖區(qū)fc.write(buffer);fout.close();} }3.5 ?讀寫結合
下面我們將看一下在結合讀和寫時會有什么情況。我們以一個名為 CopyFile.java 的簡單程序作為這個練習的基礎,它將一個文件的所有內(nèi)容拷貝到另一個文件中。CopyFile.java 執(zhí)行三個基本操作:首先創(chuàng)建一個 Buffer,然后從源文件中將數(shù)據(jù)讀到這個緩沖區(qū)中,然后將緩沖區(qū)寫入目標文件。這個程序不斷重復—讀、寫、讀、寫—直到源文件結束。
CopyFile 程序讓您看到我們?nèi)绾螜z查操作的狀態(tài),以及如何使用 clear() 和 flip() 方法重設緩沖區(qū),并準備緩沖區(qū)以便將新讀取的數(shù)據(jù)寫到另一個通道中。
3.6 ?運行 CopyFile 例子
實例讀寫結合:
// CopyFile import java.io.*; import java.nio.*; import java.nio.channels.*; public class CopyFile {static public void main(String args[]) throws Exception {//需要輸入源文件夾和目標文件的全路徑if (args.length < 2) {System.err.println("Usage: java CopyFile infile outfile");System.exit(1);}String infile = args[0];String outfile = args[1];FileInputStream fin = new FileInputStream(infile);FileOutputStream fout = new FileOutputStream(outfile);//獲得通道FileChannel fcin = fin.getChannel();FileChannel fcout = fout.getChannel();//創(chuàng)建緩沖區(qū)ByteBuffer buffer = ByteBuffer.allocate(1024);while (true) {//清空緩沖區(qū)buffer.clear();//將數(shù)據(jù)從通道讀到緩沖區(qū)中int r = fcin.read(buffer);//檢查狀態(tài)if (r == -1) {break;}//反轉(zhuǎn)buffer.flip();//寫入fcout.write(buffer);}fcin.close();fcout.close();fin.close();fout.close();} }因為緩沖區(qū)會跟蹤它自己的數(shù)據(jù),所以CopyFile 程序的內(nèi)部循環(huán) (inner loop) 非常簡單,如下所示:
fcin.read( buffer ); fcout.write( buffer );
第一行將數(shù)據(jù)從輸入通道fcin 中讀入緩沖區(qū),第二行將這些數(shù)據(jù)寫到輸出通道 fcout 。
3.7 ?檢查狀態(tài)
下一步是檢查拷貝何時完成。當沒有更多的數(shù)據(jù)時,拷貝就算完成,并且可以在 read() 方法返回 -1 是判斷這一點,如下所示:
int r = fcin.read( buffer ); if (r==-1) {break; }
3.8 ?重設緩沖區(qū)
最后,在從輸入通道讀入緩沖區(qū)之前,我們調(diào)用 clear() 方法。同樣,在將緩沖區(qū)寫入輸出通道之前,我們調(diào)用 flip() 方法,如下所示:
buffer.clear(); int r = fcin.read( buffer ); if (r==-1) {break; } buffer.flip(); fcout.write( buffer );
clear() 方法重設緩沖區(qū),使它可以接受讀入的數(shù)據(jù)。 flip() 方法讓緩沖區(qū)可以將新讀入的數(shù)據(jù)寫入另一個通道。
轉(zhuǎn)載于:https://blog.51cto.com/qiangmzsx/1409546
總結
以上是生活随笔為你收集整理的NIO入门系列之第3章:从理论到实践:NIO 中的读和写的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MemoryMappingFile泄漏分
- 下一篇: 用户软件互评