一文搞定Java NIO,以及各種奇葩流
大家好,我是哪吒。
很多朋友問我,如何才能學(xué)好IO流,對各種流的概念,云里霧里的,不求甚解。用到的時候,現(xiàn)百度,功能雖然實現(xiàn)了,但是為什么用這個?不知道。更別說效率問題了~
下次再遇到,再百度,“良性循環(huán)”。
今天,我就用一天的時間,整理一下關(guān)于Java I/O流的知識點,分享給大家。
每一種IO流,都配有示例代碼,大家可以跟著敲一遍,找找感覺~
本篇文章介紹Java NIO以及其它的各種奇葩流。
Java NIO (New I/O) 是 Java 1.4 引入的,在 Java 7 中又進(jìn)行了一些增強。NIO 可以提高 I/O 操作的效率,它的核心是通道 (Channel) 和緩沖區(qū) (Buffer)。
一、Channel
Channel 是一種新的 I/O 抽象,它與傳統(tǒng)的 InputStream 和 OutputStream 不同,Channel 可以同時進(jìn)行讀和寫操作,而且可以對其進(jìn)行更細(xì)粒度的控制。Java NIO 中最基本的 Channel 包括:
1、FileChannel代碼示例
使用FileChannel從源文件中讀取內(nèi)容并將其寫入到目標(biāo)文件。
import java.io.FileInputStream; // 引入 FileInputStream 類
import java.io.FileOutputStream; // 引入 FileOutputStream 類
import java.nio.ByteBuffer; // 引入 ByteBuffer 類
import java.nio.channels.FileChannel; // 引入 FileChannel 類
public class FileChannelExample {
public static void main(String[] args) {
String sourceFile = "source.txt";
String targetFile = "target.txt";
try {
// 使用 FileInputStream 和 FileOutputStream 打開源文件和目標(biāo)文件
FileInputStream fileInputStream = new FileInputStream(sourceFile);
FileOutputStream fileOutputStream = new FileOutputStream(targetFile);
// 獲取 FileChannel 對象
FileChannel sourceChannel = fileInputStream.getChannel();
FileChannel targetChannel = fileOutputStream.getChannel();
// 創(chuàng)建 ByteBuffer 對象
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 從源文件中讀取內(nèi)容并將其寫入目標(biāo)文件
while (sourceChannel.read(buffer) != -1) {
buffer.flip(); // 準(zhǔn)備寫入(flip buffer)
targetChannel.write(buffer); // 向目標(biāo)文件寫入數(shù)據(jù)
buffer.clear(); // 緩沖區(qū)清空(clear buffer)
}
// 關(guān)閉所有的 FileChannel、FileInputStream 和 FileOutputStream 對象
sourceChannel.close();
targetChannel.close();
fileInputStream.close();
fileOutputStream.close();
// 打印成功信息
System.out.println("文件復(fù)制成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
2、DatagramChannel代碼示例
用于 UDP 協(xié)議的數(shù)據(jù)讀寫操作。
使用DatagramChannel從一個端口讀取數(shù)據(jù)并將數(shù)據(jù)發(fā)送到另一個端口。
import java.io.IOException; // 引入 IOException 類
import java.net.InetSocketAddress; // 引入 InetSocketAddress 類
import java.nio.ByteBuffer; // 引入 ByteBuffer 類
import java.nio.channels.DatagramChannel; // 引入 DatagramChannel 類
public class DatagramChannelExample {
public static void main(String[] args) {
int receivePort = 8888;
int sendPort = 9999;
try {
// 創(chuàng)建 DatagramChannel 對象
DatagramChannel receiveChannel = DatagramChannel.open();
// 綁定接收端口
receiveChannel.socket().bind(new InetSocketAddress(receivePort));
System.out.println("接收端口 " + receivePort + " 正在等待數(shù)據(jù)...");
// 創(chuàng)建數(shù)據(jù)緩沖區(qū)對象
ByteBuffer receiveBuffer = ByteBuffer.allocate(1024);
// 從 receiveChannel 接收數(shù)據(jù)
receiveChannel.receive(receiveBuffer);
// 顯示收到的數(shù)據(jù)
System.out.println("收到的數(shù)據(jù)是:" + new String(receiveBuffer.array()));
// 關(guān)閉 receiveChannel 對象
receiveChannel.close();
// 創(chuàng)建 DatagramChannel 對象
DatagramChannel sendChannel = DatagramChannel.open();
// 創(chuàng)建數(shù)據(jù)緩沖區(qū)對象
ByteBuffer sendBuffer = ByteBuffer.allocate(1024);
// 向數(shù)據(jù)緩沖區(qū)寫入數(shù)據(jù)
sendBuffer.clear();
sendBuffer.put("Hello World".getBytes());
sendBuffer.flip();
// 發(fā)送數(shù)據(jù)到指定端口
sendChannel.send(sendBuffer, new InetSocketAddress("localhost", sendPort));
System.out.println("數(shù)據(jù)已發(fā)送到端口 " + sendPort);
// 關(guān)閉 sendChannel 對象
sendChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3、SocketChannel 和 ServerSocketChannel代碼示例
用于 TCP 協(xié)議的數(shù)據(jù)讀寫操作。
下面是一個簡單的示例,演示如何使用 SocketChannel 和 ServerSocketChannel 進(jìn)行基本的 TCP 數(shù)據(jù)讀寫操作。
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
public class TCPExample {
public static void main(String[] args) throws Exception {
// 創(chuàng)建 ServerSocketChannel 并綁定端口
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(8888));
serverSocketChannel.configureBlocking(false);
// 創(chuàng)建一個 ByteBuffer 用于接收數(shù)據(jù)
ByteBuffer buf = ByteBuffer.allocate(1024);
// 等待客戶端連接
while (true) {
SocketChannel socketChannel = serverSocketChannel.accept();
if (socketChannel != null) {
// 客戶端已連接,從 SocketChannel 中讀取數(shù)據(jù)
int bytesRead = socketChannel.read(buf);
while (bytesRead != -1) {
// 處理讀取到的數(shù)據(jù)
System.out.println(new String(buf.array(), 0, bytesRead));
// 清空 ByteBuffer,進(jìn)行下一次讀取
buf.clear();
bytesRead = socketChannel.read(buf);
}
}
}
}
}
示例代碼說明:
- 創(chuàng)建一個 ServerSocketChannel 并綁定到本地端口 8888,然后將其設(shè)置為非阻塞模式。
- 創(chuàng)建一個 ByteBuffer 用于接收數(shù)據(jù)。
- 進(jìn)入一個死循環(huán),不斷等待客戶端連接。
- 當(dāng)客戶端連接時,從 SocketChannel 中讀取數(shù)據(jù),并將讀取到的數(shù)據(jù)打印到控制臺。
- 清空 ByteBuffer,進(jìn)行下一次讀取。
需要注意的點:
- 在代碼中每次讀取結(jié)束都需要清空 ByteBuffer,否則其 position 屬性不會自動歸零,可能導(dǎo)致數(shù)據(jù)讀取不正確。
- 由于使用非阻塞模式,如果調(diào)用了 accept() 方法但沒有立即接收到客戶端連接,該方法會返回 null,需要繼續(xù)循環(huán)等待。
- 本代碼只演示了從客戶端讀取數(shù)據(jù)的部分,如果需要向客戶端發(fā)送數(shù)據(jù)需要調(diào)用SocketChannel.write()方法
如果想要向客戶端發(fā)送數(shù)據(jù),可以使用以下代碼:
// 創(chuàng)建一個 ByteBuffer 用于發(fā)送數(shù)據(jù)
ByteBuffer buf = ByteBuffer.wrap("Hello, world!".getBytes());
// 向客戶端發(fā)送數(shù)據(jù)
socketChannel.write(buf);
二、Buffer
Buffer 是一個對象,它包含一些要寫入或要讀出的數(shù)據(jù)。在 NIO 中,Buffer 可以被看作為一個字節(jié)數(shù)組,但是它的讀取和寫入操作比直接的字節(jié)數(shù)組更加高效。NIO 中最常用的 Buffer 類型包括:
1、ByteBuffer示例代碼
字節(jié)緩沖區(qū),最常用的緩沖區(qū)類型,用于對字節(jié)數(shù)據(jù)的讀寫操作。
import java.nio.ByteBuffer;
public class ByteBufferExample {
public static void main(String[] args) {
// 創(chuàng)建一個新的字節(jié)緩沖區(qū),初始容量為10個字節(jié)
ByteBuffer buffer = ByteBuffer.allocate(10);
// 向緩沖區(qū)中寫入4個字節(jié)
buffer.put((byte) 1);
buffer.put((byte) 2);
buffer.put((byte) 3);
buffer.put((byte) 4);
// 輸出緩沖區(qū)中的內(nèi)容
buffer.flip(); // 將緩沖區(qū)切換成讀模式
System.out.println(buffer.get()); // 輸出1
System.out.println(buffer.get()); // 輸出2
System.out.println(buffer.get()); // 輸出3
System.out.println(buffer.get()); // 輸出4
// 將緩沖區(qū)清空并重新寫入數(shù)據(jù)
buffer.clear();
buffer.put((byte) 5);
buffer.put((byte) 6);
buffer.put((byte) 7);
buffer.put((byte) 8);
// 輸出緩沖區(qū)中的內(nèi)容,方法同上
buffer.flip();
System.out.println(buffer.get()); // 輸出5
System.out.println(buffer.get()); // 輸出6
System.out.println(buffer.get()); // 輸出7
System.out.println(buffer.get()); // 輸出8
}
}
示例代碼說明:
- 在上面的示例中,我們使用ByteBuffer類的allocate()方法創(chuàng)建了一個新的字節(jié)緩沖區(qū),然后向緩沖區(qū)中寫入4個字節(jié)的數(shù)據(jù)。
- 接著,我們通過調(diào)用flip()方法將緩沖區(qū)切換成讀模式,并使用get()方法讀取緩沖區(qū)中的數(shù)據(jù),并按順序輸出每個字節(jié)。
- 最后,我們清空緩沖區(qū)并重新寫入數(shù)據(jù),再次將緩沖區(qū)切換成讀模式,并使用get()方法讀取緩沖區(qū)中的數(shù)據(jù)。
2、CharBuffer示例代碼
字符緩沖區(qū),用于對字符數(shù)據(jù)的讀寫操作。
import java.nio.CharBuffer;
public class CharBufferExample {
public static void main(String[] args) {
// 創(chuàng)建一個新的字符緩沖區(qū),初始容量為10個字符
CharBuffer buffer = CharBuffer.allocate(10);
// 向緩沖區(qū)中寫入4個字符
buffer.put('a');
buffer.put('b');
buffer.put('c');
buffer.put('d');
// 輸出緩沖區(qū)中的內(nèi)容
buffer.flip(); // 將緩沖區(qū)切換成讀模式
System.out.println(buffer.get()); // 輸出a
System.out.println(buffer.get()); // 輸出b
System.out.println(buffer.get()); // 輸出c
System.out.println(buffer.get()); // 輸出d
// 將緩沖區(qū)清空并重新寫入數(shù)據(jù)
buffer.clear();
buffer.put('e');
buffer.put('f');
buffer.put('g');
buffer.put('h');
// 輸出緩沖區(qū)中的內(nèi)容,方法同上
buffer.flip();
System.out.println(buffer.get()); // 輸出e
System.out.println(buffer.get()); // 輸出f
System.out.println(buffer.get()); // 輸出g
System.out.println(buffer.get()); // 輸出h
}
}
示例代碼說明:
- 在上面的示例中,我們使用CharBuffer類的allocate()方法創(chuàng)建了一個新的字符緩沖區(qū),然后向緩沖區(qū)中寫入4個字符的數(shù)據(jù)。
- 接著,我們通過調(diào)用flip()方法將緩沖區(qū)切換成讀模式,并使用get()方法讀取緩沖區(qū)中的數(shù)據(jù),并按順序輸出每個字符。
- 最后,我們清空緩沖區(qū)并重新寫入數(shù)據(jù),再次將緩沖區(qū)切換成讀模式,并使用get()方法讀取緩沖區(qū)中的數(shù)據(jù)。
3、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer 等示例代碼
import java.nio.*;
public class BasicBufferExample {
public static void main(String[] args) {
// 創(chuàng)建各種基本數(shù)據(jù)類型的緩沖區(qū),初始容量為10
ShortBuffer shortBuf = ShortBuffer.allocate(10);
IntBuffer intBuf = IntBuffer.allocate(10);
LongBuffer longBuf = LongBuffer.allocate(10);
FloatBuffer floatBuf = FloatBuffer.allocate(10);
DoubleBuffer doubleBuf = DoubleBuffer.allocate(10);
// 向緩沖區(qū)中寫入數(shù)據(jù)
shortBuf.put((short) 1);
intBuf.put(2);
longBuf.put(3L);
floatBuf.put(4.0f);
doubleBuf.put(5.0);
// 反轉(zhuǎn)緩沖區(qū),切換到讀模式
shortBuf.flip();
intBuf.flip();
longBuf.flip();
floatBuf.flip();
doubleBuf.flip();
// 讀取緩沖區(qū)中的數(shù)據(jù)
System.out.println(shortBuf.get()); // 輸出1
System.out.println(intBuf.get()); // 輸出2
System.out.println(longBuf.get()); // 輸出3
System.out.println(floatBuf.get()); // 輸出4.0
System.out.println(doubleBuf.get()); // 輸出5.0
}
}
示例代碼說明:
- 在上面的示例中,我們分別創(chuàng)建了ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer等基本數(shù)據(jù)類型的緩沖區(qū)。
- 接著,我們向這些緩沖區(qū)中寫入了對應(yīng)數(shù)據(jù)類型的數(shù)據(jù)。
- 然后我們通過調(diào)用flip()方法,將緩沖區(qū)切換成讀模式,并通過get()方法讀取緩沖區(qū)中的數(shù)據(jù),并按順序輸出每一個數(shù)據(jù)類型的內(nèi)容。
三、Selector
Selector 是 Java NIO 類庫中的一個重要組件,它用于監(jiān)聽多個 Channel 的事件。在一個線程中,通過 Selector 可以監(jiān)聽多個 Channel 的 IO 事件,并實現(xiàn)了基于事件響應(yīng)的架構(gòu)。Selector 可以讓單個線程處理多個 Channel,因此它可以提高多路復(fù)用的效率。
1、Selector讓單線程處理多個Channel的代碼示例
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
public class SelectorExample {
public static void main(String[] args) throws IOException {
// 創(chuàng)建一個ServerSocketChannel,監(jiān)聽本地端口
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress("localhost", 8080));
serverSocketChannel.configureBlocking(false);
// 創(chuàng)建一個Selector,并將serverSocketChannel注冊到Selector上
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server started on port 8080");
while (true) {
// 如果沒有任何事件發(fā)生,則阻塞等待
selector.select();
// 處理事件
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isAcceptable()) {
// 處理新的連接請求
ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
SocketChannel clientChannel = serverChannel.accept();
clientChannel.configureBlocking(false);
System.out.println("Accepted connection from " + clientChannel.getRemoteAddress());
clientChannel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// 處理讀事件
SocketChannel clientChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = clientChannel.read(buffer);
String message = new String(buffer.array(), 0, bytesRead);
System.out.println("Received message from " + clientChannel.getRemoteAddress() + ": " + message);
// 回寫數(shù)據(jù)
ByteBuffer outputBuffer = ByteBuffer.wrap(("Echo: " + message).getBytes());
clientChannel.write(outputBuffer);
}
// 從待處理事件集合中移除當(dāng)前事件
keyIterator.remove();
}
}
}
}
2、示例代碼說明
- 使用ServerSocketChannel監(jiān)聽本地8080端口,并將ServerSocketChannel注冊到Selector上。
- 在while循環(huán)中,我們通過調(diào)用select()方法等待事件發(fā)生,如果有事件發(fā)生,則從Selector中獲取待處理事件集合,然后遍歷事件集合,處理每個事件。
- 如果當(dāng)前事件是新的連接請求,則接受該連接,并將對應(yīng)的SocketChannel注冊到Selector上,使用OP_READ模式表示可以讀取數(shù)據(jù)。
- 如果當(dāng)前事件是可讀的,則讀取SocketChannel中的數(shù)據(jù)并進(jìn)行回寫,回寫時使用ByteBuffer包裝需要回寫的數(shù)據(jù),并將其寫入到SocketChannel中。
- 最后,我們從待處理事件集合中移除當(dāng)前事件。
四、ZipInputStream 和 ZipOutputStream
ZipInputStream 和 ZipOutputStream 可以用于處理 ZIP 文件格式,ZipInputStream 可以從 ZIP 文件中讀取數(shù)據(jù),ZipOutputStream 可以向 ZIP 文件中寫入數(shù)據(jù)。
1、ZipInputStream示例代碼
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipExample {
public static void main(String[] args) throws IOException {
// 輸入文件路徑和輸出壓縮文件路徑
String inputFile = "/path/to/input/file";
String outputFile = "/path/to/output/file.zip";
// 創(chuàng)建ZipOutputStream,并設(shè)置壓縮級別
ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(outputFile));
zipOutputStream.setLevel(9);
// 讀取需要壓縮的文件到文件輸入流
FileInputStream fileInputStream = new FileInputStream(inputFile);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
// 設(shè)置壓縮文件內(nèi)部的名稱
ZipEntry zipEntry = new ZipEntry(inputFile);
zipOutputStream.putNextEntry(zipEntry);
// 寫入壓縮文件
byte[] buf = new byte[1024];
int len;
while ((len = bufferedInputStream.read(buf)) > 0) {
zipOutputStream.write(buf, 0, len);
}
bufferedInputStream.close();
zipOutputStream.closeEntry();
zipOutputStream.close();
System.out.println("File compressed successfully");
}
}
示例代碼說明:
- 首先,我們創(chuàng)建ZipOutputStream并設(shè)置壓縮級別。
- 接著,我們創(chuàng)建輸入文件的FileInputStream,并使用BufferedInputStream包裝它。
- 我們接著設(shè)置壓縮文件內(nèi)部的名稱,并使用zipOutputStream.putNextEntry()方法將其寫入ZipOutputStream中。
- 最后,我們從緩沖區(qū)讀取文件數(shù)據(jù)并將其寫入ZipOutputStream中。最后關(guān)閉輸入流和ZipOutputStream。
2、ZipOutputStream示例代碼
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class UnzipExample {
public static void main(String[] args) throws IOException {
// 輸入壓縮文件路徑和輸出文件路徑
String inputFile = "/path/to/input/file.zip";
String outputFile = "/path/to/output/file";
// 創(chuàng)建ZipInputStream
ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(inputFile));
// 循環(huán)讀取壓縮文件中的條目
ZipEntry zipEntry = zipInputStream.getNextEntry();
while (zipEntry != null) {
// 如果是目錄,則創(chuàng)建空目錄
if (zipEntry.isDirectory()) {
new File(outputFile + File.separator + zipEntry.getName()).mkdirs();
} else { // 如果是文件,則輸出文件
FileOutputStream fileOutputStream = new FileOutputStream(outputFile + File.separator
+ zipEntry.getName());
byte[] buf = new byte[1024];
int len;
while ((len = zipInputStream.read(buf)) > 0) {
fileOutputStream.write(buf, 0, len);
}
fileOutputStream.close();
}
zipInputStream.closeEntry();
zipEntry = zipInputStream.getNextEntry();
}
zipInputStream.close();
System.out.println("File uncompressed successfully");
}
}
示例代碼說明:
- 使用ZipInputStream從指定輸入文件中解壓文件到指定的輸出文件夾中。
- 我們創(chuàng)建ZipInputStream,然后循環(huán)讀取壓縮文件中的條目。如果當(dāng)前條目是目錄,則創(chuàng)建空目錄,并使用mkdirs()方法創(chuàng)建目錄。如果當(dāng)前條目是文件,則使用FileOutputStream將文件寫入到指定的輸出文件中。
- 最后關(guān)閉當(dāng)前ZipEntry,并通過getNextEntry()方法獲取ZipInputStream中的下一個條目。
五、GZIPInputStream 和 GZIPOutputStream
GZIPInputStream 和 GZIPOutputStream 可以用于進(jìn)行 GZIP 壓縮,GZIPInputStream 可以從壓縮文件中讀取數(shù)據(jù),GZIPOutputStream 可以將數(shù)據(jù)寫入壓縮文件中。
1、GZIPInputStream代碼示例
import java.io.*;
import java.util.zip.GZIPOutputStream;
public class GzipExample {
public static void main(String[] args) throws IOException {
// 輸入文件路徑和輸出壓縮文件路徑
String inputFile = "/path/to/input/file";
String outputFile = "/path/to/output/file.gz";
// 創(chuàng)建GZIPOutputStream,并設(shè)置壓縮級別
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(new FileOutputStream(outputFile));
gzipOutputStream.setLevel(9);
// 讀取需要壓縮的文件到文件輸入流
FileInputStream fileInputStream = new FileInputStream(inputFile);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
// 寫入壓縮文件
byte[] buf = new byte[1024];
int len;
while ((len = bufferedInputStream.read(buf)) > 0) {
gzipOutputStream.write(buf, 0, len);
}
bufferedInputStream.close();
gzipOutputStream.close();
System.out.println("File compressed successfully");
}
}
示例代碼說明:
- 使用GZIPOutputStream將指定的輸入文件壓縮成輸出文件。
- 首先,創(chuàng)建GZIPOutputStream并設(shè)置壓縮級別。
- 接著,創(chuàng)建輸入文件的FileInputStream,并使用BufferedInputStream包裝它。
- 接著從緩沖區(qū)讀取文件數(shù)據(jù)并將其寫入GZIPOutputStream中。最后關(guān)閉輸入流和GZIPOutputStream。
2、GZIPOutputStream代碼示例
import java.io.*;
import java.util.zip.GZIPInputStream;
public class GunzipExample {
public static void main(String[] args) throws IOException {
// 輸入壓縮文件路徑和輸出文件路徑
String inputFile = "/path/to/input/file.gz";
String outputFile = "/path/to/output/file";
// 創(chuàng)建GZIPInputStream
GZIPInputStream gzipInputStream = new GZIPInputStream(new FileInputStream(inputFile));
// 輸出文件
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
byte[] buf = new byte[1024];
int len;
while ((len = gzipInputStream.read(buf)) > 0) {
fileOutputStream.write(buf, 0, len);
}
gzipInputStream.close();
fileOutputStream.close();
System.out.println("File uncompressed successfully");
}
}
示例代碼說明:
- 使用GZIPInputStream從指定輸入文件中解壓文件到指定的輸出文件中。
- 首先,我們創(chuàng)建GZIPInputStream,然后從緩沖區(qū)讀取文件數(shù)據(jù)并將其寫入到指定的輸出文件中。
- 最后,我們關(guān)閉輸入流和輸出流。
六、ByteArrayInputStream 和 ByteArrayOutputStream
ByteArrayInputStream 和 ByteArrayOutputStream 分別是 ByteArrayInputStream 和 ByteArrayOutputStream 類的子類,它們可以用于對字節(jié)數(shù)組進(jìn)行讀寫操作。
1、ByteArrayInputStream 代碼示例
import java.io.ByteArrayInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
public class ByteArrayInputStreamExample {
public static void main(String[] args) throws IOException {
// 用字符串初始化一個字節(jié)數(shù)組,作為輸入數(shù)據(jù)源
String input = "Hello, world!";
byte[] inputBytes = input.getBytes();
// 創(chuàng)建一個ByteArrayInputStream,使用輸入數(shù)據(jù)源
ByteArrayInputStream inputStream = new ByteArrayInputStream(inputBytes);
// 讀取并輸出輸入流中的數(shù)據(jù)
byte[] buf = new byte[1024];
int len;
while ((len = inputStream.read(buf)) != -1) {
System.out.println(new String(buf, 0, len));
}
// 關(guān)閉輸入流
inputStream.close();
}
}
示例代碼說明:
- 使用“Hello, world!”字符串創(chuàng)建了一個字節(jié)數(shù)組作為輸入數(shù)據(jù)源,并使用ByteArrayInputStream將其包裝成輸入流。
- 使用一個循環(huán)從輸入流中讀取數(shù)據(jù),并使用new String()方法將其轉(zhuǎn)換成字符串并輸出到控制臺。
- 最后,關(guān)閉輸入流。
2、ByteArrayOutputStream代碼示例
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class ByteArrayOutputStreamExample {
public static void main(String[] args) {
String input = "Hello World!";
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] output;
try {
outputStream.write(input.getBytes());
output = outputStream.toByteArray();
System.out.println(new String(output));
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
} finally {
try {
outputStream.close();
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
}
示例代碼說明:
- 在這個例子中,創(chuàng)建了一個ByteArrayOutputStream對象 outputStream,并向其寫入一個字符串"Hello World!"。然后,我們使用toByteArray()方法將結(jié)果轉(zhuǎn)換為一個字節(jié)數(shù)組,并打印出來。
- 注意:在使用ByteArrayOutputStream時,要確保在不再需要它時關(guān)閉它以確保所有的字節(jié)都被刷新到輸出流中。
七、總結(jié)
本文為您講解了 Java I/O、NIO 以及其他一些流的基本概念、用法和區(qū)別。Java I/O 和 NIO 可以完成很多復(fù)雜的輸入輸出操作,包括文件操作、網(wǎng)絡(luò)編程、序列化等。其他流技術(shù)可以實現(xiàn)壓縮、讀寫字節(jié)數(shù)組等功能。在進(jìn)行開發(fā)時,根據(jù)具體需求選擇不同的流技術(shù)可以提高程序效率和開發(fā)效率。
本文轉(zhuǎn)載自微信公眾號「哪吒編程」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系哪吒編程公眾號。