## 一、简介
在Java的I/O体系中,节点流是直接与数据源或数据汇(目的地)相连的流。它们构成了数据传输的最底层操作,是构建更复杂的I/O操作的基础。理解节点流对于深入掌握Java的I/O系统至关重要。
## 二、文件相关的节点流
### 1. `FileInputStream`
- **功能与特点**
- `FileInputStream`是字节输入节点流,用于从文件中读取字节数据。它直接与文件系统中的文件建立连接,按照字节顺序读取文件内容。这意味着它可以处理任何类型的文件,无论是文本文件、二进制文件(如图片、音频等)。
- 例如,当读取一个二进制图像文件时,`FileInputStream`可以逐个字节地获取文件中的数据,而不需要对文件内容进行任何特殊的解释(因为它只是处理字节)。
- **示例代码**
```java
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamExample {
public static void main(String[] args) {
try {
File file = new File("example.txt");
FileInputStream fis = new FileInputStream(file);
int data;
while ((data = fis.read())!= -1) {
System.out.print((char) data);
}
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
```
- 在这个示例中,我们创建了一个`FileInputStream`对象来读取`example.txt`文件。通过`read`方法逐个字节地读取文件内容,直到到达文件末尾(`read`返回 -1)。
### 2. `FileOutputStream`
- **功能与特点**
- `FileOutputStream`是字节输出节点流,用于将字节数据写入文件。它直接操作文件系统中的文件,将字节流按照顺序写入文件。如果文件不存在,它可以创建新文件;如果文件已经存在,根据构造函数的不同参数设置,可以选择覆盖原有文件内容或者追加内容到文件末尾。
- 例如,当我们想要保存从网络上下载的二进制文件(如一个软件安装包)到本地磁盘时,可以使用`FileOutputStream`将字节数据写入到指定的文件中。
- **示例代码**
```java
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamExample {
public static void main(String[] args) {
try {
File file = new File("output.txt");
FileOutputStream fos = new FileOutputStream(file);
String data = "Hello, World!";
byte[] byteData = data.getBytes();
fos.write(byteData);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
```
- 这里我们创建了一个`FileOutputStream`对象来写入`output.txt`文件。将字符串"Hello, World!"转换为字节数组后,使用`write`方法将字节数据写入文件。
### 3. `FileReader`
- **功能与特点**
- `FileReader`是字符输入节点流,专门用于读取文本文件中的字符数据。与`FileInputStream`不同,`FileReader`在读取数据时会考虑字符编码,能够正确地将字节转换为字符。它以字符为单位读取文件内容,使得处理文本文件更加方便和直观。
- 例如,当读取一个包含中文字符的文本文件时,`FileReader`可以正确地将字节按照合适的编码(如UTF - 8)转换为字符,而不会出现乱码问题(前提是编码设置正确)。
- **示例代码**
```java
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderExample {
public static void main(String[] args) {
try {
File file = new File("example.txt");
FileReader fr = new FileReader(file);
int data;
while ((data = fr.read())!= -1) {
System.out.print((char) data);
}
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
```
- 在这个示例中,`FileReader`从`example.txt`文本文件中逐个字符地读取数据,直到文件末尾。
### 4. `FileWriter`
- **功能与特点**
- `FileWriter`是字符输出节点流,用于将字符数据写入文本文件。它同样会根据系统默认的字符编码(或者可以指定编码)将字符转换为字节后写入文件。如果文件不存在,会创建新文件;如果文件存在,默认会覆盖原有文件内容,但也可以设置为追加模式。
- 例如,当我们想要记录一些日志信息到文本文件时,可以使用`FileWriter`将字符形式的日志内容写入到文件中。
- **示例代码**
```java
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterExample {
public static void main(String[] args) {
try {
File file = new File("output.txt");
FileWriter fw = new FileWriter(file);
fw.write("This is a sample text.");
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
```
- 这里`FileWriter`将指定的字符串写入到`output.txt`文件中。
## 三、数组相关的节点流
### 1. `ByteArrayInputStream`
- **功能与特点**
- `ByteArrayInputStream`是字节输入节点流,它的数据源是一个字节数组。这在处理内存中的字节数据时非常有用,例如,当我们已经将一些数据读取到字节数组中,想要对这些数据进行类似文件读取的操作(如按照顺序逐个字节处理)时,可以使用`ByteArrayInputStream`。
- 它允许我们将字节数组视为一个输入流的数据源,从而可以复用很多针对输入流的操作方法。
- **示例代码**
```java
import java.io.ByteArrayInputStream;
public class ByteArrayInputStreamExample {
public static void main(String[] args) {
byte[] byteArray = {65, 66, 67};
ByteArrayInputStream bais = new ByteArrayInputStream(byteArray);
int data;
while ((data = bais.read())!= -1) {
System.out.print((char) data);
}
}
}
```
- 在这个示例中,我们创建了一个包含字符'A'、'B'、'C'(对应的ASCII码值)的字节数组,然后使用`ByteArrayInputStream`将字节数组作为数据源进行读取操作。
### 2. `ByteArrayOutputStream`
- **功能与特点**
- `ByteArrayOutputStream`是字节输出节点流,它将字节数据输出到一个字节数组中。这在需要在内存中构建字节数据时非常有用,例如,当我们想要动态地生成一些字节数据(如将多个小的字节数据片段组合成一个大的字节数组)时,可以使用`ByteArrayOutputStream`。
- 它提供了一种方便的方式来操作字节数据,最后可以通过`toByteArray`方法获取生成的字节数组。
- **示例代码**
```java
import java.io.ByteArrayOutputStream;
public class ByteArrayOutputStreamExample {
public static void main(String[] args) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
baos.write(65);
baos.write(66);
baos.write(67);
} catch (java.io.IOException e) {
e.printStackTrace();
}
byte[] result = baos.toByteArray();
for (byte b : result) {
System.out.print((char) b);
}
}
}
```
- 在这个示例中,我们使用`ByteArrayOutputStream`向字节数组中写入字符'A'、'B'、'C'(对应的ASCII码值),然后获取生成的字节数组并打印出对应的字符。
## 四、管道相关的节点流
### 1. `PipedInputStream`和`PipedOutputStream`
- **功能与特点**
- `PipedInputStream`和`PipedOutputStream`是用于线程间通信的字节流。`PipedOutputStream`用于向管道写入字节数据,`PipedInputStream`用于从管道读取字节数据。它们必须成对使用,并且在使用前需要连接起来。
- 例如,在一个多线程的应用中,一个线程负责生成数据,另一个线程负责处理数据,就可以使用`PipedInputStream`和`PipedOutputStream`来实现数据在两个线程之间的传递。
- **示例代码**
```java
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
class DataProducer implements Runnable {
private PipedOutputStream pos;
public DataProducer(PipedOutputStream pos) {
this.pos = pos;
}
@Override
public void run() {
try {
String data = "Hello, Pipe!";
byte[] byteData = data.getBytes();
pos.write(byteData);
pos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class DataConsumer implements Runnable {
private PipedInputStream pis;
public DataConsumer(PipedInputStream pis) {
this.pis = pis;
}
@Override
public void run() {
try {
int data;
while ((data = pis.read())!= -1) {
System.out.print((char) data);
}
pis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class PipedStreamExample {
public static void main(String[] args) {
try {
PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream();
pos.connect(pis);
Thread producerThread = new Thread(new DataProducer(pos));
Thread consumerThread = new Thread(new DataConsumer(pis));
producerThread.start();
consumerThread.start();
producerThread.join();
consumerThread.join();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
```
- 在这个示例中,`DataProducer`线程使用`PipedOutputStream`向管道写入数据,`DataConsumer`线程使用`PipedInputStream`从管道读取数据。
节点流在Java的I/O系统中提供了直接与各种数据源和数据目的地交互的能力,是构建复杂I/O操作的基础组件。通过合理地使用不同类型的节点流,我们可以有效地处理文件、内存数据以及线程间的数据传输等各种I/O相关的任务。