引言
Java IO(Input输入/Output输出)框架扮演着至关重要的角色,它是数据交换和文件处理的基石。
数据输入到计算机内存的过程即输入,反之输出到外部存储(比如数据库,文件,远程主机)的过程即输出。数据传输过程类似于水流,因此称为 IO 流。
一、Java IO体系概览
Java IO 流有40多个类,他们都是从如下 4 个抽象类基类中派生出来的。
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
字节流和字符流有什么区别
- 字节流:以字节(8位)为单位进行数据的读写。它是计算机中最基本的数据传输单元,适用于处理包括文本、图像、音频、视频等在内的二进制数据。
- 字符流:以字符为单位进行数据的读写。字符流在处理时,会根据指定的字符编码(如UTF-8、GBK等)将字符转换为字节进行处理。由于一个字符可能占用多个字节(具体取决于编码方式),主要用于处理文本数据。
IO 流的分类
类型 | 名称 | 说明 |
---|---|---|
按功能分 | 输入流,输出流 | 输入流的类以InputStream, Reader为后缀。输出流的类以OutputStream, Writer未后缀。 |
按照类型分 | 字节流、字符流 | 节点流的类以InputStream,OutputStream为后缀,字符流以Reader,Writer为后缀 |
按角色或功能层次 | 节点流(低级流、原始流)、包装流(处理流、高级流) | 节点流 它是直接从数据源或目的地读写数据的流。除了对原数据进行读取的节点流外,其他都是包装流 |
下图展示IO流系统图-常用的类
二、IO操作之文件与目录的操作
介绍File类,包括如何创建、删除文件或目录,检查文件属性等。
package file;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
public class studyOfFile {
@Test
public void createFile() throws IOException {
String filePath = "/Users/wu/file";
File file = new java.io.File(filePath);
/*创建文件*/
file.createNewFile();
/*查看文件的一下属性*/
System.out.println("创建文件成功 ~");
System.out.println("文件名字: " + file.getName());
System.out.println("文件是否存在: " + file.exists());
System.out.println("文件是否是文件: " + file.isFile());
System.out.println("文件的路径: " + file.getAbsolutePath());
System.out.println("文件是否拥有读权限 " + file.canRead());
System.out.println("文件是否存在: " + file.exists());
/*删除文件*/
file.delete();
System.out.println("删除文件成功 ~");
System.out.println("文件是否存在: " + file.exists());
}
@Test
public void createDirectory() {
String directory = "/Users/wu/studyIo";
File file = new java.io.File(directory);
/*创建目录*/
file.mkdir();
/*查看目录的一下属性*/
System.out.println("创建目录成功 ~");
System.out.println("文件是否是文件: " + file.isFile());
System.out.println("文件是否是目录: " + file.isDirectory());
/*删除目录*/
file.delete();
System.out.println("删除目录成功 ~");
System.out.println("目录是否存在: " + file.exists());
}
}
文件操作执行结果:
目录操作的执行结果:
三、以案例学习OI流
在本小节将展示一下内容:
字节流:FileInputStream和FileOutStream
字符流:FileReader和FileWiter
包装流:BufferedInputStream
<-- FileReader和FileWiter的用法和下面的例子很类似,就不在写demo了-->
FileInputStream例子
这个例子将演示如何使用FileInputStream来读取文件内容,并使用FileOutputStream将读取的内容写入另一个文件。
package demo;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamExample {
public static void main(String[] args) {
String sourcePath = "/Users/wu/studyIo/source.txt";
String targetPath = "/Users/wu/studyIo/target.txt";
FileInputStream fis = null;
FileOutputStream fos = null;
try {
/*创建一个source.txt文件 用于从source.txt文件中读取去数据*/
fis = new FileInputStream(sourcePath);
/*创建一个target.txt文件 用于将读到的数据写到target.txt文件中*/
fos = new FileOutputStream(targetPath);
/*设置缓冲区的大小 一次读取1024字节*/
byte[] buffer = new byte[1024];
int length;
/*read方法放回读取的字节数,读取完毕返回-1*/
while ((length = fis.read(buffer)) > -1) {
/*边读边写*/
fos.write(buffer, 0, length);
}
System.out.println("文件复制完成。");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
/*记得关闭 释放资源*/
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
/*真正执行写的操作,否则写入不成功*/
fos.write(0);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
这里我遇到了一个问题:
fis = new FileInputStream(sourcePath);按理可以直接创建文件的。因为它的源代码是这样写的
我会报错
手动创建上两个文件就不会报错了。
至于为什么不创建文件而报错,我也没想明白。
BufferedInputStream例子
这个例子将展示如何使用BufferedInputStream来提高文件读取的效率。
package demo;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class BufferedStreamExample {
public static void main(String[] args) {
String sourcePath = "/Users/wu/studyIo/source.txt";
BufferedInputStream bis = null;
try {
bis = new BufferedInputStream(new FileInputStream(sourcePath));
int data = bis.read();
while (data != -1) {
System.out.print((char) data);
data = bis.read();
}
System.out.println("\n文件读取完成。");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
运行结果:
这里面会出现乱码问题,原因是用的是BufferedInputStream他是字节流,一个中文是占3个字节,它将他分成了一个一个字节读,就会乱码,把BufferedInputStream换为BufferedReader字符流就可以解决乱码问题。(要考虑文件编码格式)
四、以对象处理流来学习序列化和反序列化
序列化:保持数据时,保持数据的值和数据类型
反序列化:恢复数据时,恢复数据的值和数据类型
package demo;
import java.io.*;
public class SerializationDemo {
public static void main(String[] args) {
String sourcePath = "/Users/wu/studyIo/employee.txt";
// 序列化过程
try (FileOutputStream fileOut = new FileOutputStream(sourcePath);
ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
Employee emp = new Employee("John Doe", 30);
out.writeObject(emp);
System.out.println("Serialized data is saved in employee.ser");
} catch (IOException i) {
i.printStackTrace();
}
// 反序列化过程
Employee emp = null;
try (FileInputStream fileIn = new FileInputStream(sourcePath);
ObjectInputStream in = new ObjectInputStream(fileIn)) {
emp = (Employee) in.readObject();
System.out.println("Deserialized Employee...");
System.out.println("Employee : " + emp);
} catch (IOException i) {
i.printStackTrace();
return;
} catch (ClassNotFoundException c) {
System.out.println("Employee class not found");
c.printStackTrace();
return;
}
}
}
五、补充字符转换流,打印流和随机访问流
六、IO异常处理
- 用try-catch-finally语句块处理异常。
- 类名后面添加 throws IOException 声明可以有IO异常发生,但不做处理。
参考资料
哔哩哔哩 -->韩顺平老师讲的IO专题视频
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。