常见的流类
字节流:
FileInputStream:从文件读取字节数据。
FileOutputStream:向文件写入字节数据。
BufferedInputStream:为输入流提供缓冲功能,提高读取效率。
BufferedOutputStream:为输出流提供缓冲功能,提高写入效率。
DataInputStream 和 DataOutputStream:用于读取和写入基本数据类型和字符串。
字符流:
FileReader:从文件读取字符数据。
FileWriter:向文件写入字符数据。
BufferedReader:为字符输入流提供缓冲功能,提高读取效率。
BufferedWriter:为字符输出流提供缓冲功能,提高写入效率。
InputStreamReader 和 OutputStreamWriter:用于在字节流和字符流之间进行转换。
巧记:
字节流和字符流都是File开头的,缓冲流都是在此基础上把File换为Buffered
使用缓冲流的步骤
缓冲流提供了缓冲的输入功能,从而提高了从其他输入流(如文件输入流)中读取数据的效率。当你创建一个BufferedInputStream实例时,你需要将一个已经存在的输入流作为参数传递给它。
创建文件对象(如果需要处理文件):
使用File类创建一个表示文件的对象。
创建节点流对象:
根据文件的读写需求,创建相应的节点流对象(如FileInputStream、FileOutputStream、FileReader、FileWriter)。
创建缓冲流对象:
将节点流对象作为参数传递给缓冲流的构造函数,创建缓冲流对象。
进行读写操作:
使用缓冲流对象提供的读写方法(如read()、write())进行数据的读写。
关闭资源:
在完成读写操作后,关闭缓冲流和节点流以释放资源。通常,关闭最外层的缓冲流即可,因为关闭缓冲流时会自动关闭其包装的节点流(但这不是绝对的,具体取决于流的实现)。
数据被读取到哪里了
当使用输入流(如 FileInputStream, BufferedReader 等)读取文件时,数据并不是直接“读取到某个地方”,而是被逐块或逐个字符地读取到内存中,然后可以决定如何处理这些数据。
对于字符流(如 Reader 和其子类),读取的数据通常以字符序列的形式存在,并可以方便地转换为字符串。对于字节流(如 InputStream 和其子类),读取的数据以字节序列的形式存在,你可能需要将其转换为字符串或其他格式才能进一步处理。
字符流读取文件内容
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class ReadFileExample {
public static void main(String[] args) {
String filePath = "example.txt";
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedReader是一个包装流(wrapper stream),它提供了缓冲的输入功能,从而提高了从其他输入流(如文件输入流)中读取数据的效率。当你创建一个BufferedReader实例时,你需要将一个已经存在的输入流作为参数传递给它。
字符流写入数据到文件
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class WriteFileExample {
public static void main(String[] args) {
String filePath = "example.txt";
String content = "Hello, World!";
try (BufferedWriter bw = new BufferedWriter(new FileWriter(filePath))) {
bw.write(content);
} catch (IOException e) {
e.printStackTrace();
}
}
}
字节流读取文件内容
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class ReadFileBytesExample {
public static void main(String[] args) {
String filePath = "example.bin";
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath))) {
int data;
while ((data = bis.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedInputStream是一个包装流(wrapper stream),它提供了缓冲的输入功能,从而提高了从其他输入流(如文件输入流)中读取数据的效率。当你创建一个BufferedInputStream实例时,你需要将一个已经存在的输入流作为参数传递给它
字节流写入数据到文件
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class WriteFileBytesExample {
public static void main(String[] args) {
String filePath = "example.bin";
byte[] data = "Hello, Byte Stream!".getBytes(); //将待写入的数据转换为字节序列
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath))) {
bos.write(data);
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用字节流(如 FileOutputStream)写入数据到文件时,需要将待写入的数据转换为字节序列,因为字节流是以字节为单位进行数据传输的。字符串(String)本身是一个字符序列,而字符在计算机内部通常是以特定的编码方式(如 UTF-8, UTF-16, ISO-8859-1 等)表示为字节的。
当调用 String 类的 getBytes() 方法时,它会根据平台的默认字符编码(在某些 Java 环境中,这通常是 UTF-8,但这不是保证的,并且可能因环境和 JVM 配置而异)将字符串转换为字节数组(byte[])。这个字节数组随后可以通过字节流写入到文件中。
关于异常
当使用流(Stream)进行输入/输出(I/O)操作时,经常会遇到可能抛出的异常。这些异常可能源于多种原因,例如文件未找到、文件无法读取或写入、磁盘空间不足、权限问题等。
为什么需要try-catch?
- 异常捕获:
try-catch块:捕获在try块中抛出的异常,并在catch块中处理它们。
- 资源管理:
在使用流时,通常需要打开和关闭资源(如文件、网络连接等)。如果在关闭资源之前发生异常,那么资源可能不会被正确关闭,导致资源泄漏。将流的打开和关闭操作放在try-with-resources语句中(这是try-catch的一个扩展),可以确保资源在try块执行完毕后自动关闭,即使发生了异常。
try-catch与try-with-resources
从Java 7开始,引入了try-with-resources语句,它是try-catch块的一个增强版本,专门用于管理实现了AutoCloseable或Closeable接口的资源(如流)。使用try-with-resources可以确保资源在try块结束时自动关闭,无论是否发生异常。