文章摘要: Java 平台提供的一组输入/输出(I/O)相关的 API。
介绍
简要说明
- 通过数据流、序列化和文件系统提供系统输入和输出。
- Java 平台提供的一组输入/输出(I/O)相关的 API。
- 用于处理数据流、文件操作以及其他与 I/O 相关的任务。
- 提供了丰富的类和接口,以支持不同类型的 I/O 操作。
主要功能
- 流操作:提供了字节流(InputStream 和 OutputStream)和字符流(Reader 和 Writer)来处理二进制和文本数据。
- 文件操作:提供了 File 类来表示文件和目录路径信息,并可以进行创建、删除、重命名等操作。
- 序列化与反序列化:支持对象的序列化(将对象状态保存到字节流)和反序列化(从字节流恢复对象状态)。
- 缓冲区操作:提供了缓冲流(BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter)来提高 I/O 操作的效率。
- 数据操作:提供了 DataInputStream 和 DataOutputStream 用于读写基本数据类型。
- 对象流操作:提供了 ObjectInputStream 和 ObjectOutputStream 用于对象的序列化和反序列化。
- 随机访问文件:提供了 RandomAccessFile 类用于随机访问文件内容。
注意事项
- 资源管理:在使用 I/O 资源时,应该始终注意资源的关闭,以避免资源泄露。Java 7 引入了 try-with-resources 语句来简化资源管理。
- 异常处理:I/O 操作可能抛出 IOException,因此需要妥善处理这些异常。
- 性能考虑:使用缓冲流可以提高 I/O 操作的性能,特别是在处理大量数据时。
- 字符编码:在处理文本数据时,需要特别注意字符编码问题,以避免乱码。
适用场景
- 文件读写:当需要读取或写入文件时,
java.io提供了丰富的类和方法来支持这些操作。 - 网络通信:在网络编程中,经常需要使用
java.io来处理网络数据流。 - 数据序列化:当需要将对象状态持久化或通过网络传输对象时,可以使用
java.io的序列化机制。 - 系统间数据交换:
java.io可以用于不同系统或组件之间的数据交换。 - 基础数据处理:在处理基本数据类型和字符串时,
java.io提供了方便的 API。
基本概念
- 流(Stream): 数据的流动,可以是输入流(读取数据)或输出流(写入数据)。
- 字节流(Byte Stream): 以字节为单位进行读写,适用于所有类型的文件数据。
- 字符流(Character Stream): 以字符为单位进行读写,适用于文本文件。
- 过滤器流(Filter Stream): 用于装饰其他流,提供额外的功能,如缓冲、数据压缩、加密等。
主要类和接口
输入流(InputStream 和 Reader)
- InputStream: 所有输入字节流的超类,提供读取字节的基本方法。
- Reader: 所有输入字符流的超类,提供读取字符的基本方法。
- FileInputStream: 用于从文件系统中的文件读取数据。
- FileReader: 用于从文件系统中的文件读取文本数据。
- BufferedInputStream: 用于包装另一个输入流,提供缓冲功能,提高读取效率。
- BufferedReader: 用于包装另一个输入流,提供缓冲功能,提高文本读取效率。
输出流(OutputStream 和 Writer)
- OutputStream: 所有输出字节流的超类,提供写入字节的基本方法。
- Writer: 所有输出字符流的超类,提供写入字符的基本方法。
- FileOutputStream: 用于向文件系统中的文件写入数据。
- FileWriter: 用于向文件系统中的文件写入文本数据。
- BufferedOutputStream: 用于包装另一个输出流,提供缓冲功能,提高写入效率。
- BufferedWriter: 用于包装另一个输出流,提供缓冲功能,提高文本写入效率。
其他重要类
- File: 提供文件和目录路径名的操作。
- RandomAccessFile: 支持随机访问文件的读写操作。
- ObjectInputStream/ObjectOutputStream: 用于对象的序列化和反序列化。
- InputStreamReader/OutputStreamWriter: 用于在字节流和字符流之间转换。
学习总结
文件操作
- 文件读写: 学习如何使用 FileInputStream/FileOutputStream 和 FileReader/FileWriter 进行文件的基本读写操作。
- 随机访问文件: 了解 RandomAccessFile 的使用,它可以跳转到文件的任意位置进行读写。
流操作
- 流类型: 区分字节流和字符流,了解它们的使用场景。
- 缓冲流: 学习使用 BufferedInputStream/BufferedReader 和 BufferedOutputStream/BufferedWriter 来提高 I/O 操作的效率。
- 过滤器流: 掌握如何使用过滤器流(如 DataInputStream/DataOutputStream)来处理不同类型的数据。
序列化
- 对象序列化: 学习如何使用 ObjectOutputStream 和 ObjectInputStream 来序列化和反序列化对象。
资源管理
- 关闭流: 确保在不再需要时关闭流,释放系统资源,可以使用 try-with-resources 语句来自动关闭资源。
- 异常处理: 学习如何处理 IOException 和其他相关异常。
实践建议
- 使用缓冲: 总是使用缓冲流来包装原始流,以提高性能。
- 异常处理: 在 I/O 操作中总是包含异常处理逻辑。
- 资源管理: 使用 try-with-resources 语句来管理资源,避免资源泄露。
- 文件路径: 注意操作系统之间的文件路径差异。
- 编码问题: 在处理文本文件时,注意字符编码和解码的问题。
java.io.File
相关信息
- File对象用于代表硬盘中的一个文件或文件夹。
- File对象只能对文件本身进行操作,不能读写文件里面存储的数据进行操作。
- File对象能接收一个不存在的文件或文件夹。
- 支持“绝对路径、相对路径”的文件路径。
- 类库路径:
java.io.File
实例化File对象
| 方法 | 说明 |
|---|---|
new File(String <文件路径>) | 根据文件路径创建文件对象 |
new File(String <父级路径>, String <子路径>) | 根据父级路径和子路径名称创建文件对象 |
new File(File <父级路径>, String <子路径>) | 根据父级路径对应文件对象和子路径名称 |
创建
| 方法 | 说明 |
|---|---|
<File>.createNewFile() | 创建文件,若创建成功则返回true |
<File>.mkdir() | 创建文件夹,只能创建一级文件夹,若创建成功则返回true |
<File>.mkdirs() | 创建文件夹,可以创建多层级文件夹,若创建成功则返回true |
删除
| 方法 | 说明 |
|---|---|
<File>.delete() | 删除文件或空目录,若删除成功则返回true |
修改
| 方法 | 说明 |
|---|---|
<File>.renameTo() | 修改文件名称 |
查询
| 方法 | 说明 |
|---|---|
<File>.exists() | 判断文件是否存在,若存在则返回true |
<File>.isFile() | 判断文件是否是文件,若是文件则返回true |
<File>.isDirectory() | 判断文件是否是文件夹,若是文件夹则返回true |
<File>.getName() | 获取文件的名称(包含后缀) |
<File>.length() | 获取文件的大小,返回字节个数 |
<File>.lastModified() | 获取文件的最后修改时间 |
<File>.getPath() | 获取创建文件时使用的路径 |
<File>.getAbsolutePath() | 获取文件的绝对路径 |
<File>.getParent() | 获取文件所在的父级目录 |
<File>.list() | 获取当前目录下所有的“一级文件和文件夹的名称”,返回String[] |
<File>.listFiles() | 获取当前目录下所有的“一级文件和文件夹的对象”,返回File[] |
<File>.canWrite():是否可写<File>.isFile():是否隐藏
案例
分析:
- 输入文件夹,作为查找范围
- 遍历全部一级文件对象,判断是否是文件
- 若是文件,判断是否是自己想要的文件
- 若是文件夹,则获取该文件夹下全部一级文件,重复上述过程
代码
import java.io.File;
import java.util.ArrayList;
public class Main {
public static void main(String[] ages) {
// 创建存放查找结果的文件列表
ArrayList<String> fileList = new ArrayList<>();
// 调用方法
// - 传入查找目录范围(File对象)
// - 查找的目标文件名
// - 保存查找到的文件列表
searchFile(new File("/home/magictable/Projec/"), "Main.java", fileList);
// 判断文件列表中的最新数据是否为0
if (fileList.size() == 0) {
System.out.println("未找到目标文件");
}
// 输出文件列表中存储的最新数据
for (int i=0; i < fileList.size(); i++) {
// 格式化输出结果
System.out.println("结果"+ (i+1) + ":" + fileList.get(i));
}
}
/**
* 搜索指定目录范围下的目标文件
* @param dir 查找的目录范围(File文件)
* @param fileName 查找的目标文件名
* @param fileList 保存查找到的文件列表
*/
public static void searchFile(File dir, String fileName, ArrayList<String> fileList) {
// 判断输入的`dir`文件夹:
// - 是否不存在
// - 是否是一个文件
// - 是否是空目录
if (!dir.exists() || dir.isFile() || dir == null) {
return;
}
// 获取`dir`目录下的全部一级文件对象
File[] fileArray = dir.listFiles();
// 判断文件夹大小是否为“0字节”(用于判断是否拥有该文件夹的权限)
// 是否是空的“文件夹”
if (fileArray.length > 0 && fileArray != null) {
// 获取该目录下的全部一级文件对象
for (File f : fileArray) {
// 判断文件是否是文件
if (f.isFile()) {
// 判断文件是否是我们要找的
if (f.getName().equals(fileName)) {
// 将当前文件对象的绝对路径保存到文件列表中
fileList.add(f.getAbsolutePath());
}
}
else { // 当前文件是一个文件夹
// 调用该方法进行重复查找过程,递归算法
searchFile(f, fileName, fileList);
}
}
}
}
}
编码和解码
- 需要写异常处理。
- 编码与解码使用的字符集必须一致,才不会出现乱码。
编码
| 方法 | 说明 |
|---|---|
<String>.getBytes() | 使用平台的默认字符集将该String对象编码为一些列字节,返回byte[] |
<String>.getBytes(String charsetName) | 使用指定的字符集将该String对象编码为一些列字节,返回byte[] |
解码
| 方法 | 说明 |
|---|---|
new String(byte[] bytes) | 通过使用平台默认字符集解码指定的字节数组,返回新的String |
new String(byte[] bytes, String charsetName) | 通过指定的字符集解码指定的字节数组,返回新的String |
IO流基础知识
- I是Input,输入流,负责把数据读取到内存中。
- O是Output,输出流,负责把数据写入到(硬盘/网络)中。
- 内存与存储设备之间传输数据的通道。
- 用于读写数据。
框架图
IO流的分类
按方向
- 输入流:将“存储设备/网络”中的内容读入到“内存/本地”中。
- 输出流:将“内存/本地”中的内容写入到“存储设备/网络”中。
按单位
- 字节流:以字节为单位,适合读写所有类型的文件。
- 字符流:以字符为单位,只适合读写文本类型的文件。
按功能
- 节点流:具有实际传输数据的读写功能,基础流(字节流、字符流)。
- 过滤流:在节点流的基础之上增强功能,高级流(缓存流、转换流、打印流、数据流、序列化流)。
字节输入流
以内存为基准,将磁盘上的数据以“字节”的形式“读取输入”到内存中。
使用完后需要关闭流。
包路径:
java.io.FileInputStream
构造方法
| 方法 | 说明 |
|---|---|
new FileInputStream(File file) | 将File文件对象作为参数进行传输 |
new FileInputStream(String name) | 将文件路径作为参数进行传输 |
new FileInputStream(FileDescriptor fdObj) |
相关方法
| 方法 | 说明 |
|---|---|
<FileInputStream>.read() | 从输入流中读取一个字节的数据,返回int,当没有数据时返回-1 |
<FileInputStream>.read(byte[] b) | 从输入流中读取b个字节的长度,返回int,当没有数据时返回-1 |
<FileInputStream>.available() | 将当前字节输入流对应的文件对象字节数据装到一个字节数组返回 |
案例
- 设定固定大小的缓存区,进行多字节批量读取数据。
- 缺点:读取性能差,频繁与硬盘交互,无法解决乱码问题。
try {
// 实例化File对象,添加要操作的文件
File file = new File("/home/abc.text");
// 实例化字节输入流对象,传入需要读取的File文件对象
FileInputStream inputFile = new FileInputStream(file);
// 类似缓存区,一批次能读取多少字节
byte[] byteData = new byte[3];
// 记录当前批次读取了多少字节
int len;
while ((len = inputFile.read(byteData)) != -1) {
// 读取的内容是根据data读取多少字节,就输出到多少字节。
// 该步骤是正在“解码”操作,即将二进制文件转换为字符串数据
String fileData = new String(byteData, 0, len);
// 在控制台输出显示
String.out.print(fileData);
}
// 释放输出流对象
inputFile.close();
} catch (IOException e) {
System.out.println("文件操作报错:" + e.getMessage());
}
字节输出流
以内存为基准,将内存上的数据以“字节”的形式“写入输出”到磁盘中。
使用完后需要关闭流。
包路径:
java.io.FileOutputStream
构造方法
| 方法 | 说明 |
|---|---|
new FileOutputStream(File file) | (覆盖)创建字节输入流管道与源文件对象接通 |
new FileOutputStream(String filepath) | (覆盖)创建字节输入流管道与源文件路径接通 |
new FileOutputStream(File file, boolean append) | (追加)创建字节输入流管道与源文件对象接通,可追加数据 |
new FileOutputStream(String filepath, boolean append) | (追加)创建字节输入流管道与源文件对象接通,可追加数据 |
相关方法
- 提示:写入数据若文件不存在则自动创建。
| 方法 | 说明 |
|---|---|
<FileOutputStream>.write(int a) | 写入一个字节到文件中 |
<FileOutputStream>.write(byte[] buffer) | 写入一个字节数组到文件中 |
<FileOutputStream>.write(byte[] buffer, int pos, int len) | 写入一个字节数组的一部分到文件中 |
<FileOutputStream>.flush() | 刷新,将缓冲区中的内容写入到文件中。 |
<FileOutputStream>.close() | 释放流,包含了刷新 |
案例
try {
// 实例化File对象,添加要操作的文件
File file = new File("/home/abc.text");
// 实例化字节输出流对象,传入需要写入的File文件对象
FileOutputStream outputFile = new FileOutputStream(file);
// 需要写入文件的数据
String data = "你好,世界。";
// 将数据进行“编码”操作,即将字符串数据转换为二进制文件
byte[] byteData = data.getBytes();
// 将编码后的数据,通过字节输出流对象,写入到文件
outputFile.write(byteData);
// 释放输出流对象
outputFile.close();
} catch (IOException e) {
System.out.println("文件复制失败:" + e.getMessage());
}
字符输入流
以内存为基准,可以吧文件中的数据以“字符”的形式“读取输入”到内存中。
使用完后需要关闭流。
包路径:
java.io.FileReader
构造方法
| 方法 | 说明 |
|---|---|
new FileReader(File file) | 创建字符输入流管道与源文件接通 |
new FileReader(String pathname) | 创建字符输入流管道与源文件接通 |
相关方法
| 方法 | 说明 |
|---|---|
<FileReader>.read() | 每次读取一个字符返回,若没有数据可读时返回-1 |
<FileReader>.read(char[] buffer) | 每次用一个字符数组去读取数据,返回字符数组读取了多少字节,若没有数据可读时返回-1 |
案例
// 实例化File对象,添加要操作的文件
File file = new File("/home/file.text");
try (
// 实例化字符输入流,添加要读取的File对象
FileReader readerFile = new FileReader(file);
) {
// 创建临时存储空间,存储读取出的字符
char[] charArray = new char[1024];
// 记住当批次读取了多少字符
int len;
while ((len=readerFile.read(charArray)) != -1) {
// 将字符列表“解码”成字符串
String data = new String(charArray, 0, len);
// 将结果输出到控制台
System.out.print(data);
}
} catch (IOException e) {
System.out.println("文件复制失败:" + e.getMessage());
}
字符输出流
- 以内存为基准,把内存中的数据以“字符”的形式“写入输出”到文件中。
- 使用完后需要关闭流。
- 包路径:
java.io.FileWriter
构造方法
| 方法 | 说明 |
|---|---|
new FileWriter(File file) | (覆盖)创建字节输出流管道与源文件对象接通 |
new FileWriter(String filepath) | (覆盖)创建字节输出流管道与源文件路径接通 |
new FileWriter(File file, boolean append) | (追加)创建字节输出流管道与源文件对象接通,可追加数据 |
new FileWriter(String filepath, boolean append) | (追加)创建字节输出流管道与源文件路径接通,可追加数据 |
相关方法
| 方法 | 说明 |
|---|---|
<FileWriter>.write(int a) | 写入一个字符 |
<FileWriter>.write(String str) | 写入一个字符串 |
<FileWriter>.write(String str, int off, int len) | 写入一个字符串的一部分 |
<FileWriter>.write(char[] cbuf) | 写入一个字符数组 |
<FileWriter>.write(char[] cbuf, int off, int len) | 写入字符数组的一部分 |
<FileWriter>.flush() | 刷新,将缓冲区中的内容写入到文件中。 |
<FileWriter>.close() | 释放流,包含了刷新 |
案例
// 实例化File对象,添加要操作的文件
File file = new File("/home/file.text");
try (
// 实例化字符输出流对象,传入需要写入的File文件对象
FileWriter fileWriter = new FileWriter(file);
) {
// 需要写入文件的数据
String data = "你好,世界。";
// 将数据通过字符输出流对象,写入到File文件
fileWriter.write(data);
} catch (IOException e) {
System.out.println("文件写入失败:" + e.getMessage());
}
缓冲流
- 添加缓冲流,提高原始数据流读写数据的性能,减少与硬盘交互的次数。
- 缓冲流类似添加“字符数组”,分批次读取数据。
类别
BufferedInputStream:缓冲字节输入流BufferedOotputStream:缓冲字节输出流BufferedReader:缓冲字符输入流BufferedWriter:缓冲字符输出流提示
- 缓冲流需要传入输入流或输出流,因此需要先创建原始数据流。
- 缓冲流包装原始数据流。
构造方法
| 方法 | 说明 |
|---|---|
new BufferedInputStream(InputStream is) | (缓冲字节输入流)默认8192byte缓冲区大小 |
new BufferedInputStream(InputStream is, int size) | (缓冲字节输入流)指定缓冲区大小 |
new BufferedOotputStream(OutputStream os) | (缓冲字节输出流)默认8192byte缓冲区大小 |
new BufferedOotputStream(OutputStream os, int size) | (缓冲字节输出流)指定缓冲区大小 |
new BufferedReader(Reader fr) | (缓冲字符输入流)默认8192byte缓冲区大小 |
new BufferedReader(Reader fr, int sz) | (缓冲字符输入流)指定缓冲区大小 |
new BufferedWriter(Writer fw) | (缓冲字符输出流)默认8192byte缓冲区大小 |
new BufferedWriter(Writer fw, int sz) | (缓冲字符输出流)指定缓冲区大小 |
相关方法
| 方法 | 说明 |
|---|---|
<BufferedReader>.readLine() | 缓冲字符输入流,读取一行数据,返回String,没有数据时返回null |
<BufferedWriter>.newLine() | 缓冲字符输出流,换行,没有返回值 |
案例 - 字节流操作
import java.io.IOException; // IO异常处理类
import java.io.File; // File文件对象
import java.io.FileInputStream; // 文本字节输入流
import java.io.FileOutputStream; // 文本字节输出流
import java.io.BufferedInputStream; // 文本字节缓冲输入流
import java.io.BufferedOutputStream; // 文本字节缓冲输出流
public class Main {
public static void main(String[] ages) {
// 实例化File对象,添加要读取的文件
File file = new File("/home/file.text");
// 实例化File对象,添加要复制写入的文件
File fileCopy = new File("/home/fileCopy.text");
try (
// 实例化字节输入流对象,添加要读取的File对象
FileInputStream is = new FileInputStream(file);
// 实例化字节缓冲输入流对象,包装原始字节输入流,即添加缓冲区
BufferedInputStream bis = new BufferedInputStream(is);
// 实例化字节输出流对象,添加要写入的File对象
FileOutputStream of = new FileOutputStream(fileCopy);
// 实例化字节缓冲输出流对象,包装原始字节输出流,即添加缓冲区
BufferedOutputStream bos = new BufferedOutputStream(of);
) {
// 创建临时存储空间,存储读取出的字节
byte[] byteData = new byte[1024];
// 记录当前批次存储了多少字节
int len;
// 循环与硬盘交互
while ((len = bis.read(byteData)) != -1) {
// 读取的内容是根据data读取多少字节,就输出到多少字节。
// 将当批次获得的字节数据,通过字节缓冲输出流,写入到另一个File文件
bos.write(byteData, 0, len);
}
} catch (IOException e) {
System.out.println("文件复制失败:" + e.getMessage());
}
}
}
案例 - 字符流操作
import java.io.IOException; // IO异常处理类
import java.io.File; // File文件对象
import java.io.FileReader; // 文本字符输入流
import java.io.FileWriter; // 文本字符输出流
import java.io.BufferedReader; // 文本字符缓冲输入流
import java.io.BufferedWriter; // 文本字符缓冲输出流
public class Main {
public static void main(String[] ages) {
// 实例化File对象,添加需要复制的源文件
File file = new File("/home/file.text");
// 实例化File对象,添加需要复制的新文件
File fileCopy = new File("/home/fileCopy.text");
try (
// 实例化字符输入流,添加要读取的File对象
FileReader fr = new FileReader(file);
// 实例化字符缓冲输入流,包装原始字符输入流,即添加缓冲区
BufferedReader br = new BufferedReader(fr);
// 实例化字符输出流,添加要写入的File对象
FileWriter fw = new FileWriter(fileCopy);
// 实例化字符缓冲输出流,包装原始字符输出流,即添加缓冲区
BufferedWriter bw = new BufferedWriter(fw);
) {
// 创建临时存储空间,存储读取出的字符
char[] charArray = new char[1024];
// 记录当前批次存储了多少字符
int len;
// 循环与硬盘交互
while ((len = br.read(charArray)) != -1) {
// 将当批次获得的字符数据,通过字节缓冲输出流,写入到另一个File文件
bw.write(charArray, 0, len);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
转换流
- 若代码编码和被读取的文本文件的编码不一致,则使用字符流读取文本文件时就会出现乱码。
- 解决不同编码时,字符流读取文本内容乱码的问题。
- 解决思路:先获取文件的原始字节流,再将其按真实的字符集编码转换成字符输入流,这样字符输入流中的字符就不会乱码。
类别
InputStreamReader字符输入转换流:控制输入读取的文件用什么字符集解码。OutputStreamWrite字符输出转换流:控制输出写入的文件用什么字符集编码。
构造方法
| 方法 | 说明 |
|---|---|
new InputStreamReader(InputStream is) | (字符输入转换流)把原始的字节输入流,按照代码默认编码转换成字符输入流(与直接使用FileReader的效果一样) |
new InputStreamReader(InputStream is, String charset) | (字符输入转换流)将原始字节输入流,按照指定字符集编码转成字符输入流 |
new OutputStreamWrite(OutputStream is) | (字符输出转换流)将原始字节数据流,按照文件默认编码转换成字符输出流 |
new OutputStreamWrite(OutputStream is, String charset) | (字符输出转换流)将原始字节数据流,按照指定编码转换成字符输出流 |
打印流
PrintStream:字节打印流PrintWriter:字符打印流
构造方法
| 字节打印流方法 | 说明 |
|---|---|
new PrintStream(OutputStream fos) | 打印流直接通向字节输出流对象 |
new PrintStream(File file) | 打印流直接通向File文件对象 |
new PrintStream(String fileName) | 打印流直接通向文件路径 |
new PrintStream(String fileName, Charset charset) | 指定写入的字符编码 |
new PrintStream(OutputStream out, boolean autoFlush) | 指定字节输出流,是否自动刷新 |
new PrintStream(OutputStream out, boolean autoFlush, String encoding) | 指定字节输出流,是否自动刷新,字符编码 |
| 字符打印流方法 | 说明 |
|---|---|
new PrintWriter(OutputStream fos) | 打印流直接通向字符输出流对象 |
new PrintWriter(File file) | 打印流直接通向File文件对象 |
new PrintWriter(String fileName) | 打印流直接通向文件路径 |
new PrintWriter(String fileName, Charset charset) | 指定写入的字符编码 |
new PrintWriter(OutputStream out, boolean autoFlush) | 指定字符输出流,是否自动刷新 |
new PrintWriter(OutputStream out, boolean autoFlush, String encoding) | 指定字符输出流,是否自动刷新,字符编码 |
相关方法
| 字节打印流方法 | 说明 |
|---|---|
<PrintStream>.println(<任意数据>) | 打印任意数据,有换行 |
<PrintStream>.print(<任意数据>) | 打印任意数据,不会换行 |
<PrintStream>.write(<数据>) | 可以支持写字节数据 |
| 字符打印流方法 | 说明 |
|---|---|
<PrintWriter>.println(<任意数据>) | 打印任意数据,有换行 |
<PrintWriter>.print(<任意数据>) | 打印任意数据,不会换行 |
<PrintWriter>.write(<数据>) | 可以支持写字节数据 |
数据流
- 允许把数据和其类型一并写出去。
类别
DataInputStream:输入数据流DataOutputStream:输出数据流
构造方法
| 输入数据流方法 | 说明 |
|---|---|
new DataInputStream(OutputStream out) | 创建新数据输出流包基础的字节输入流 |
| 输出数据流方法 | 说明 |
|---|---|
new DataOutputStream(OutputStream out) | 创建新数据输出流包基础的字节输出流 |
相关方法
| 输入数据流方法 | 说明 |
|---|---|
<DataInputStream>.readerByte() | 将byte类型数据写入基础的字节输出流 |
<DataInputStream>.readerInt() | 将int类型数据写入基础的字节输出流 |
<DataInputStream>.readerDouble() | 将double类型数据写入基础的字节输出流 |
<DataInputStream>.readerUTF() | 将字符串数据以UTF-8编码成字节写入基础的字节输出流 |
| 输出数据流方法 | 说明 |
|---|---|
<DataOutputStream>.writeByte(int v) | 将byte类型数据写入基础的字节输出流 |
<DataOutputStream>.writeInt(int v) | 将int类型数据写入基础的字节输出流 |
<DataOutputStream>.writeDouble(Double v) | 将double类型数据写入基础的字节输出流 |
<DataOutputStream>.writeUTF(String str) | 将字符串数据以UTF-8编码成字节写入基础的字节输出流 |
序列化流
类别
ObjectInputStream:(对象字节输入流)对象反序列化,把文件里的java对象读出来。ObjectOutputStream:(对象字节输出流)对象序列化,把java对象写入到文件中去。提示:
- 对象如果需要参与序列化,则必须让该对象的类实现序列化接口
java.io.Serializable,用于表示一个标记,通过获取对象是否有该方法来判断对象是否运行被序列化。
构造方法
| 方法 | 说明 |
|---|---|
new ObjectInputStream(OutputStream fis) | 创建对象字符输入流,包装基础的字节输入流 |
new ObjectOutputStream(OutputStream fos) | 创建对象字符输出流,包装基础的字节输出流 |
相关方法
| 方法 | 说明 |
|---|---|
<ObjectOutputStream>.readObject() | 将对象输入读取出来,返回Object |
<ObjectOutputStream>.writeObject(object o) | 将对象输出写入到文件 |
案例 - 对象序列化
import java.io.*;
public class Main {
public static void main(String[] ages) {
// 实例化File对象
File file = new File("/home/file.text");
try (
// 实例化文件字节输出流,添加需要写入数据的File对象
FileOutputStream fos = new FileOutputStream(file);
// 实例化对象字节输出流,添加文件字节输出流
ObjectOutputStream oos = new ObjectOutputStream(fos);
) {
// 创建对象,该对象的类必须继承`Serializable`接口
User user = User("姓名", 18);
// 通过对象通过对象字节输出流,将对象写入文件
oos.writeObject(user);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
案例 - 对象反序列化
import java.io.*;
public class Main {
public static void main(String[] ages) {
// 实例化File对象
File file = new File("/home/file.text");
try (
// 实例化文件字节输入流,添加需要读取数据的File对象
FileInputStream fos = new FileInputStream(file);
// 实例化对象字节输入流,添加文件字节输入流
ObjectIntputStream oos = new ObjectIntputStream(fos);
) {
// 通过对象通过对象字节输出流,将对象读取出来
// (重点)获得将对象文件后,需要手动强转成User对象数据类型
User user = (User)oos.writeObject(user);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
IO流的资源释放操作
try-catch-finally
案例
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Main {
public static void main(String[] ages) {
// 实例化File对象,添加要读取的文件
File file = new File("/home/file.text");
// 实例化File对象,添加要复制写入的文件
File fileCopy = new File("/home/fileCopy.text");
// 实例化字节输入流对象
InputStream inputFile = null;
// 实例化字节输出流对象
OutputStream outputFile = null;
try {
// 传入需要读取的File文件对象
inputFile = new FileInputStream(file);
// 传入需要写入的File文件对象
outputFile = new FileOutputStream(fileCopy);
// 类似缓存区,一批次能读取多少字节
byte[] byteData = new byte[3];
// 记录当前批次读取了多少字节
int len;
while ((len = inputFile.read(byteData)) != -1) {
// 读取的内容是根据data读取多少字节,就输出到多少字节。
// 将读取到的字节数据,通过字节输出流对象,写入到文件
outputFile.write(byteData, 0, len);
}
} catch (IOException e) {
System.out.println("文件复制失败:" + e.getMessage());
} finally {
// 释放输出流对象资源
try {
// 判断输出流对象是否已经关闭
if (outputFile != null) {
// 释放输出流对象
outputFile.close();
}
} catch (IOException e) {
e.printStackTrace();
}
// 释放输入流对象资源
try {
// 判断输入流对象是否已经关闭
if (inputFile != null) {
// 释放输出流对象
inputFile.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
try-with-resource
案例
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Main {
public static void main(String[] ages) {
// 实例化File对象,添加要读取的文件
File file = new File("/home/file.text");
// 实例化File对象,添加要复制写入的文件
File fileCopy = new File("/home/fileCopy.text");
try (
// 实例化字节输入流对象,传入需要读取的File文件对象
InputStream inputFile = new FileInputStream(file);
// 实例化字节输出流对象,传入需要写入的File文件对象
OutputStream outputFile = new FileOutputStream(fileCopy);
) {
// 类似缓存区,一批次能读取多少字节
byte[] byteData = new byte[3];
// 记录当前批次读取了多少字节
int len;
while ((len = inputFile.read(byteData)) != -1) {
// 读取的内容是根据data读取多少字节,就输出到多少字节。
// 将读取到的字节数据,通过字节输出流对象,写入到文件
outputFile.write(byteData, 0, len);
}
} catch (IOException e) {
System.out.println("文件复制失败:" + e.getMessage());
}
}
}