概述
Java I/O(输入/输出)系统提供了强大的数据读写能力,是Java编程中处理数据输入输出的核心机制。本文将深入介绍Java I/O流的概念、分类、File类使用方法以及各种处理流的应用场景。
一、I/O流基本概念
I/O流**是Java中处理输入输出的抽象概念:
- I (Input)**:输入,指数据从外部流向程序
- O (Output)**:输出,指数据从程序流向外部
- 流(Stream)**:像管道或通道,能够双向输送数据
二、I/O流分类体系
Java I/O流可按不同维度进行分类:
1. 按流向分
- 输入流:从数据源读取数据到程序
- 输出流:从程序写入数据到目的地
2. 按处理单位分
- 字节流:以字节(8位)为单位处理数据,适合所有类型文件
- 字符流:以字符(16位)为单位处理数据,适合文本文件
3. 按功能分
- 节点流:直接连接数据源的管道,没有任何额外功能
- 处理流:连接其他管道的管道,提供缓冲、转换等增强功能
三、File类:文件与目录操作
Java遵循"万事万物皆对象"的理念,通过File类表示文件和目录路径名。
基本文件操作示例
```java
public static void main(String[] args) throws IOException {
File file = new File("E:\\dz18\\dz181.txt");
System.out.println(file.getName()); // 文件名及后缀名: dz18.txt
System.out.println(file.getPath()); // 文件地址: E:\dz18\dz18.txt
System.out.println(file.length()); // 文件大小: 764
System.out.println(file.canRead()); // 是否可读: true
System.out.println(file.isFile()); // 是否为文件: true
if(!file.exists()) {
file.createNewFile(); // 创建文件
System.out.println("文件创建成功");
} else {
file.delete(); // 删除文件
}
}
```
目录操作示例
```java
public static void main(String[] args) {
File file = new File("E:\\dz18");
if(!file.isFile()) { // 判断是否为文件夹
if(file.exists()) { // 判断文件夹是否存在
file.delete();
System.out.println("删除");
} else {
file.mkdirs(); // 创建多层文件夹
file.mkdir(); // 创建单层文件夹
System.out.println("创建");
}
} else {
System.out.println("是文件");
}
// 获取目录下所有子文件和子目录
String[] list = file.list();
for(String s : list) {
System.out.println(s);
}
}
```
递归遍历目录结构
```java
// 模拟杀毒软件全盘扫描功能
public void getFileInfo(File file) {
File[] files = file.listFiles(); // 获取目录下所有文件对象
int count = 0;
for(int i = 0; i < files.length; i++) {
if(files[i].isFile()) {
for(int j = 0; j <= count; j++) {
System.out.print("\t");
}
System.out.println(files[i].getName());
} else {
System.out.println(files[i].getName());
getFileInfo(files[i]); // 递归调用
count++;
}
}
}
public static void main(String[] args) {
File file = new File("D:\\盛世吉软\\1.java基础");
new FileTest().getFileInfo(file);
}
```
四、处理流详解
1. 缓冲流(Buffered Stream)
自带缓冲区(默认大小8192字节),提高I/O效率:
```java
// 使用缓冲流复制文件
public static void main(String[] args) throws IOException {
// 1. 获取数据源对象
File eFile = new File("E:\\dz18\\dz18.txt");
File cFile = new File("C:\\Users\\a\\Desktop\\dz18.txt");
// 2. 获取管道流对象:先获得节点流,再获得处理流
FileReader fr = new FileReader(eFile);
BufferedReader br = new BufferedReader(fr);
FileWriter fw = new FileWriter(cFile);
BufferedWriter bw = new BufferedWriter(fw);
// 3. 开始读写
String str = br.readLine();
int count = 0;
while(str != null) {
bw.write(str);
bw.newLine();
count++;
str = br.readLine();
}
System.out.println(count + "行数据已复制");
// 4. 关闭流资源:只需要关闭高级流
bw.close(); // 自带刷新管道功能bw.flush()
br.close();
}
```
2. 转换流(Conversion Stream)
实现字节流与字符流之间的转换:
```java
// 使用转换流处理文件
public static void main(String[] args) throws IOException {
// 1. 获取数据源对象
File eFile = new File("E:\\dz18\\dz18.txt");
File cFile = new File("C:\\Users\\a\\Desktop\\dz18.txt");
// 2. 获取管道流对象
FileInputStream fis = new FileInputStream(eFile);
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
FileOutputStream fos = new FileOutputStream(cFile);
OutputStreamWriter osw = new OutputStreamWriter(fos);
BufferedWriter bw = new BufferedWriter(osw);
// 3. 开始读写
String str = br.readLine();
while(str != null) {
bw.write(str);
bw.newLine();
str = br.readLine();
}
// 4. 关闭流资源
bw.close();
br.close();
System.out.println("复制成功!");
}
```
3. 数据流(Data Stream)
在传输数据的同时保存数据类型信息:
```java
public static void main(String[] args) throws IOException {
// 1. 获取数据源对象
File file = new File("E:\\dz18\\123.txt");
// 2. 获取管道流对象
FileOutputStream fos = new FileOutputStream(file);
DataOutputStream dos = new DataOutputStream(fos);
FileInputStream fis = new FileInputStream(file);
DataInputStream dis = new DataInputStream(fis);
// 3. 开始写入和读取(必须按相同顺序)
dos.writeBoolean(true);
dos.writeUTF("你好");
dos.writeDouble(123.4);
dos.writeInt(9);
// 取出:必须按照写入的顺序
if(dis.readBoolean()) {
System.out.println("boolean值是true!");
}
System.out.println(dis.readUTF());
System.out.println(dis.readDouble() * dis.readInt());
// 4. 关闭流资源
dis.close();
dos.close();
}
```
4. 对象流(Object Stream)
实现对象的序列化与反序列化:
```java
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 1. 获取数据源对象
File file = new File("E:\\dz18\\obj.txt");
// 2. 获取管道流对象
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
// 3. 序列化与反序列化操作
Person person = new Person("张三", 23, "123456");
oos.writeObject(person);
Object object = ois.readObject();
if(object instanceof Person) {
Person p = (Person) object;
System.out.println(p.getId());
}
// 4. 关闭流资源
ois.close();
oos.close();
System.out.println("存储成功!");
}
```
五、对象序列化注意事项
1. 实现Serializable接口:需要序列化的对象所属类必须实现此接口
2. 添加serialVersionUID:在反序列化时,JVM会比较字节流中的serialVersionUID与程序中相应实体类的serialVersionUID
- ID值相同:进行反序列化操作
- ID值不同:报错并停止反序列化,起到安全保护作用
3. transient修饰符:被transient修饰的属性不会被序列化
4. 嵌套对象序列化:被序列化的类的内部所有属性必须是可序列化的
- 如果有其他类作为属性,这些类也必须实现Serializable接口并拥有serialVersionUID
5. 静态变量:序列化对静态变量无效
- 静态变量被序列化时,所有对象实例将共享同一静态值
- 反序列化时无法对应具体对象实例
总结
Java I/O系统提供了丰富而强大的数据处理能力,从基本的文件操作到复杂的数据序列化,涵盖了各种应用场景。掌握这些核心概念和技术,能够帮助开发者高效处理各种数据输入输出需求,构建更加健壮的应用程序。理解流的分类体系、熟悉File类的使用方法以及掌握各种处理流的特性,是成为Java高级开发者的必备技能。

被折叠的 条评论
为什么被折叠?



