BIO 全稱 Block-IO 是一種同步且阻塞的通訊模式。是一個比較傳統的通訊方式,模式簡單,使用方便。但併發處理能力低,通訊耗時,依賴網速。
Java NIO,全程 Non-Block IO ,是 Java SE 1.4 版以後,針對網路傳輸效能最佳化的新功能。是一種非阻塞同步的通訊模式。
NIO 與原來的 I/O 有同樣的作用和目的, 他們之間最重要的區別是資料打包和傳輸的方式。原來的 I/O 以流的方式處理資料,而 NIO 以塊的方式處理資料。
面向流的 I/O 系統一次一個位元組地處理資料。一個輸入流產生一個位元組的資料,一個輸出流消費一個位元組的資料。
面向塊的 I/O 系統以塊的形式處理資料。每一個操作都在一步中產生或者消費一個資料塊。按塊處理資料比按(流式的)位元組處理資料要快得多。但是面向塊的 I/O 缺少一些面向流的 I/O 所具有的優雅性和簡單性。
Java AIO,全稱 Asynchronous IO,是非同步非阻塞的 IO。是一種非阻塞非同步的通訊模式。
在 NIO 的基礎上引入了新的非同步通道的概念,並提供了非同步檔案通道和非同步套接字通道的實現。
區別
BIO (Blocking I/O):同步阻塞 I/O 模式。
NIO (New I/O):同步非阻塞模式。
AIO (Asynchronous I/O):非同步非阻塞 I/O 模型。
適用場景
BIO 方式適用於連線數目比較小且固定的架構,這種方式對伺服器資源要求比較高,併發侷限於應用中,JDK1.4 以前的唯一選擇,但程式直觀簡單易理解。
NIO 方式適用於連線數目多且連線比較短(輕操作)的架構,比如聊天伺服器,併發侷限於應用中,程式設計比較複雜,JDK1.4 開始支援。
AIO 方式適用於連線數目多且連線比較長(重操作)的架構,比如相簿伺服器,充分呼叫 OS 參與併發操作,程式設計比較複雜,JDK7 開始支援。
使用方式
public class BioFileDemo {
public static void main(String[] args) {
BioFileDemo demo = new BioFileDemo();
demo.writeFile();
demo.readFile();
}
// 使用 BIO 寫入檔案
public void writeFile() {
String filename = "xx.txt";
try {
FileWriter fileWriter = new FileWriter(filename);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write("學程式設計就上技術派");
bufferedWriter.newLine();
System.out.println("寫入完成");
bufferedWriter.close();
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 使用 BIO 讀取檔案
public void readFile() {
String filename = "xx.txt";
try {
FileReader fileReader = new FileReader(filename);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println("讀取的內容: " + line);
}
bufferedReader.close();
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class NioFileDemo {
public static void main(String[] args) {
NioFileDemo demo = new NioFileDemo();
demo.writeFile();
demo.readFile();
}
// 使用 NIO 寫入檔案
public void writeFile() {
Path path = Paths.get("cc.txt");
try {
FileChannel fileChannel = FileChannel.open(path, EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE));
ByteBuffer buffer = StandardCharsets.UTF_8.encode("hh");
fileChannel.write(buffer);
System.out.println("寫入完成");
fileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 使用 NIO 讀取檔案
public void readFile() {
Path path = Paths.get("xx.txt");
try {
FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = fileChannel.read(buffer);
while (bytesRead != -1) {
buffer.flip();
System.out.println("讀取的內容: " + StandardCharsets.UTF_8.decode(buffer));
buffer.clear();
bytesRead = fileChannel.read(buffer);
}
fileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class AioDemo {
public static void main(String[] args) {
AioDemo demo = new AioDemo();
demo.writeFile();
demo.readFile();
}
// 使用 AsynchronousFileChannel 寫入檔案
public void writeFile() {
// 使用 Paths.get() 獲取檔案路徑
Path path = Paths.get("xx.txt");
try {
// 用 AsynchronousFileChannel.open() 開啟檔案通道,指定寫入和建立檔案的選項。
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
// 將要寫入的字串("學程式設計就上技術派")轉換為 ByteBuffer。
ByteBuffer buffer = StandardCharsets.UTF_8.encode("學程式設計就上技術派");
// 呼叫 fileChannel.write() 方法將 ByteBuffer 中的內容寫入檔案。這是一個非同步操作,因此需要使用 Future 物件等待寫入操作完成。
Future<Integer> result = fileChannel.write(buffer, 0);
// 等待寫操作完成
result.get();
System.out.println("寫入完成");
fileChannel.close();
} catch (IOException | InterruptedException | java.util.concurrent.ExecutionException e) {
e.printStackTrace();
}
}
// 使用 AsynchronousFileChannel 讀取檔案
public void readFile() {
Path path = Paths.get("xx.txt");
try {
// 指定讀取檔案的選項。
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
// 建立一個 ByteBuffer,用於儲存從檔案中讀取的資料。
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 呼叫 fileChannel.read() 方法從檔案中非同步讀取資料。該方法接受一個 CompletionHandler 物件,用於處理非同步操作完成後的回撥。
fileChannel.read(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
// 在 CompletionHandler 的 completed() 方法中,翻轉 ByteBuffer(attachment.flip()),然後使用 Charset.forName("UTF-8").decode() 將其解碼為字串並列印。最後,清空緩衝區並關閉檔案通道。
attachment.flip();
System.out.println("讀取的內容: " + StandardCharsets.UTF_8.decode(attachment));
attachment.clear();
try {
fileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
// 如果非同步讀取操作失敗,CompletionHandler 的 failed() 方法將被呼叫,列印錯誤資訊。
System.out.println("讀取失敗");
exc.printStackTrace();
}
});
// 等待非同步操作完成
Thread.sleep(1000);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}