IO流
IO流
1 File流
- 常用方法
public static void main(String[] args) throws IOException {
// 创建了一个指向E盘下的a.txt的file对象
// file对象在创建的时候不去检查文件是否存在
// 只是将当前的路径标记为一个file对象
File file = new File("E:\\svn\\第一阶段");
// 创建文件 返回值true表示创建成功
// 当且仅当这个文件不存在的时候,创建该文件
// 路径必须真实存在
// boolean newFile = file.createNewFile();
// System.out.println(newFile);
// 创建目录
// 只能创建一级的目录
// boolean mkdir = file.mkdir();
// System.out.println(mkdir);
// 创建多级目录
// boolean mkdirs = file.mkdirs();
// System.out.println(mkdirs);
// 如果是文件直接删除,如果是目录并且这个目录非空,则删除失败
// 如果要删除目录,要求目录必须没有内容
// 从计算机中彻底删除
// boolean delete = file.delete();
// System.out.println(delete);
// 获取所有的一级子文件和子目录
// File[] files = file.listFiles();
// for (File file1 : files) {
// System.out.println(file1);
// }
// 判断file是否是文件
System.out.println(file.isFile());
// 判断file是否是目录
System.out.println(file.isDirectory());
}
课堂练习:删除一个目录
public static void del(File file){
if (file.isDirectory()){
// 获取目录中的所有的子目录和子文件
File[] files = file.listFiles();
for (File file1 : files) {
del(file1);
}
}
// 删除目录/文件
file.delete();
}
统计工作空间中java文件和class文件的数量
// 统计工作空间中java文件和class文件的数量
public static void count(File file){
// 判断是否是目录
if (file.isDirectory()){
// 获取子目录
File[] files = file.listFiles();
for (File file1 : files) {
count(file1);
}
}else if (file.getName().endsWith(".java")){
javaCount++;
}else if (file.getName().endsWith(".class")){
classCount++;
}
}
- separatorChar 目录分隔符 在windows中是\ ,在linux中是/
- pathSeparatorChar: 路径分隔符 在windows中是; 在linux中是:
static int javaCount;
static int classCount;
public static void main(String[] args) throws IOException {
// 20250710
File file = new File("E:\\test\\西游记.txt");
// 判断文件是否是可执行文件 在windows中只要是可读写的都是可执行文件
// file.canExecute();
// 测试是否是可读方法 在windows中只要能打开的文件都是可读
// file.canRead();
// file.createNewFile();
// // 判断文件是否可写
// System.out.println(file.canWrite());
// // 判断文件/目录是否存在
// System.out.println(file.exists());
// // 获取绝对路径(从盘符开始的路径)
// System.out.println(file.getAbsolutePath());
// // 获取剩余空间(单位是字节)
// System.out.println(file.getFreeSpace());
// // 获取可用空间
// System.out.println(file.getUsableSpace());
// // 获取总空间
// System.out.println(file.getTotalSpace());
// // 获取文件名称
// System.out.println(file.getName());
// // 获取父目录
// System.out.println(file.getParent());
// // 获取路径
// System.out.println(file.getPath());
// // 判断是否是绝对路径
// System.out.println(file.isAbsolute());
// // 判断是否是隐藏文件
// System.out.println(file.isHidden());
// // 获取修改时间
// System.out.println(file.lastModified());
//
// File[] files = file.listFiles(new FileFilter() {
// // 把所有的子目录和子文件传递过来
// // 返回true的内容会留在最后的数组中
// @Override
// public boolean accept(File pathname) {
// return pathname.getName().matches(".*\\d.*");
// }
// });
// File[] files = file.listFiles(pathname -> pathname.getName().matches(".*\\d.*"));
// File[] files = file.listFiles(new FilenameFilter() {
// // dir 文件所在的父目录
// // name 文件名
// @Override
// public boolean accept(File dir, String name) {
// return name.matches(".*\\d.*");
// }
// });
// File[] files = file.listFiles(((dir, name) -> name.matches(".*\\d.*")));
// for (File file1 : files) {
// System.out.println(file1);
// }
// 移动并重命名
// file.renameTo(new File("E:\\test\\西游记.txt"));
// 修改最后的修改时间 单位是毫秒
// file.setLastModified(1000L);
// 设置是否是只读文件
file.setReadOnly();
// 设置是否可写
file.setWritable(false);
}
2 IO流概述
IO流:传输数据的一套机制
I: input 输入流
O:output 输出流
输入和输出是参考内存来说的

java中的流分为字节流和字符流
字符流只能处理和字符相关的文本
字节流可以处理任何类型的文件
| 输入流 | 输出流 | |
|---|---|---|
| 字符流 | Reader | Writer |
| 字节流 | InputStream | OutputStream |
以上四个都是抽象类,真正使用的应该是它们的子类
3 字符流
3.1 FileWriter
public static void main(String[] args) throws IOException {
// 字符输出流
// 创建一个新文件
// 如果原文件不存在,则使用创建的这个新文件
// 如果原文件已存在,则使用新文件覆盖原文件
// append:追加访问
FileWriter fileWriter = new FileWriter("D:\\a.txt",true);
// 写出数据
fileWriter.write("helloworld");
// 冲刷缓冲区
// fileWriter.flush();
// 关闭流 关闭流的时候会自动冲刷一次缓冲区
fileWriter.close();
fileWriter = null;
}
- 异常处理
// 字符输出流
// 创建一个新文件
// 如果原文件不存在,则使用创建的这个新文件
// 如果原文件已存在,则使用新文件覆盖原文件
// append:追加访问
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter("D:\\a.txt",true);
// 写出数据
fileWriter.write("helloworld");
// 冲刷缓冲区
// fileWriter.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
// 关闭流 关闭流的时候会自动冲刷一次缓冲区
try {
if (fileWriter != null){
fileWriter.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
fileWriter = null;
}
}
- JDK1.7 try-with-resources
public static void main(String[] args) throws IOException {
demo2(new FileWriter("D:\\a.txt"));
}
private static void demo2(FileWriter writer) {
// jdk1.7出现 try-with-resources
// 运行代码完成之后会自动关流
// 要求对象对应的类必须实现AutoCloseable接口
try (writer){
writer.write("尚马");
}catch (IOException e){
e.printStackTrace();
}
}
3.2 FileReader
public static void main(String[] args) throws IOException {
// 字符输入流
FileReader fileReader = new FileReader("D:\\a.txt");
// 一次读取一个字符 如果读取不到返回-1
// int read = fileReader.read();
// System.out.println((char)read);
// 以下方式每次读取一个字符,效率较低
// int ch;
// while ((ch = fileReader.read()) != -1){
// System.out.print((char) ch);
// }
// 一次读取多个字符 创建缓冲数组
char[] cs = new char[5];
int len;
// 返回值是读取的实际个数 读取不到返回-1
// int read = fileReader.read(cs);
// System.out.println(read);
// System.out.println(cs);
while ((len = fileReader.read(cs)) != -1){
System.out.print(new String(cs,0,len));
}
// 关流 释放资源
fileReader.close();
}
拷贝文件:
// 拷贝文件
// 创建字符输入流和字符输出流
FileReader fileReader = new FileReader("D:\\西游记.txt", Charset.forName("gbk"));
FileWriter fileWriter = new FileWriter("D:\\test\\红楼梦.txt",Charset.forName("gbk"));
// 读取内容
// 创建字符数组作为缓冲区
char[] cs = new char[1024 * 8];
// 实际读取到的个数
int len;
while ((len = fileReader.read(cs)) != -1){
// 写出到文件中
fileWriter.write(cs,0,len);
}
// 关流 从里向外关
fileWriter.close();
fileReader.close();
3.3 BufferedReader和BufferedWriter
这两个类自动具有缓冲区,读取和写入非常高效
BufferedReader属于字符输入流
BufferedWriter属于字符输出流
23种常用的设计模式之一 -- 装饰设计模式
模式:针对某一类问题的统一的处理方法
设计模式:在软件开发中针对遇到的问题所提供的统一的解决方案
装饰设计模式:利用同类对象来构建本类对象,然后对所构建的对象进行功能的改善或者增强
- BufferedReader
public static void main(String[] args) throws IOException {
// 创建字符输入流
FileReader fileReader = new FileReader("D:\\test\\红楼梦.txt", Charset.forName("gbk"));
// 装饰设计模式
BufferedReader bufferedReader = new BufferedReader(fileReader);
// 每次能够读取一行内容,读取到末尾返回null
// 读取到换行符就结束,不会读取换行符
// String s = bufferedReader.readLine();
// System.out.println(s);
String str;
while ((str = bufferedReader.readLine()) != null){
System.out.println(str);
}
// 关流
bufferedReader.close();
fileReader.close();
}
- BufferedWriter
public static void main(String[] args) throws IOException {
// 创建字符输出流
FileWriter fileWriter = new FileWriter("D:\\hello.txt");
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write("hellohello");
// 写出一个换行符
bufferedWriter.newLine();
// 关流
bufferedWriter.close();
fileWriter.close();
}
- 拷贝文件
// 拷贝文件
private static void demo3() throws IOException {
// 创建高效字符流
BufferedReader bufferedReader = new BufferedReader(new FileReader("D:\\西游记.txt",Charset.forName("gbk")));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("D:\\test\\水浒传.txt",Charset.forName("gbk")));
String str ;
while ((str = bufferedReader.readLine()) != null){
bufferedWriter.write(str);
bufferedWriter.newLine();
}
// 关流 关闭外层流,内层流也会跟着关闭
bufferedWriter.close();
bufferedReader.close();
}
- 课堂练习:统计工作空间中java代码的行数
//统计工作空间中java代码的行数
private static int count = 0;// 代码的行数
private static void demo4(File file) throws IOException {
if (file.isDirectory()){
// 获取子目录或者子文件
for (File listFile : file.listFiles()) {
demo4(listFile);
}
}else if (file.getName().endsWith(".java")){ //判断是否是java文件
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
while (bufferedReader.readLine() != null){
count++;
}
// 关闭 资源
bufferedReader.close();
}
}
4 字节流
字节流可以操作任意类型的文件
private static void demo2() throws IOException {
// 创建字节输入流
FileInputStream fileInputStream = new FileInputStream("D:\\a.txt");
// 读取数据 一次读取一个字节 读取不到返回-1
// int read = fileInputStream.read();
// System.out.println((char) read);
// 一次获取所有需要的长度 OutOfMemoryError
// byte[] bys = new byte[fileInputStream.available()];
// int len = fileInputStream.read(bys);
// System.out.println(len);
// for (byte by : bys) {
// System.out.println((char)by);
// }
// 返回实际读取到的个数 读取不到返回-1
// int len = fileInputStream.read(bys);
// System.out.println(bys);
// System.out.println(len);
// 推荐
// int len;
// while ((len = fileInputStream.read(bys)) != -1){
// System.out.print(new String(bys,0,len));
// }
// 读取所有的字节
byte[] bytes = fileInputStream.readAllBytes();
for (byte aByte : bytes) {
System.out.print((char)aByte);
}
// 关流
fileInputStream.close();
}
private static void demo1() throws IOException {
// 创建字节输出流
FileOutputStream fileOutputStream = new FileOutputStream("D:\\a.txt");
// 写出数据到文件中
// 字节流没有缓冲区
fileOutputStream.write("helloworld".getBytes());
// 关流
fileOutputStream.close();
}
- 课堂练习:拷贝文件
private static void demo3() throws IOException {
// 拷贝文件
// 创建字节输入和输出流
FileInputStream fileInputStream = new FileInputStream("E:\\jdk-17.0.15_doc-all.zip");
FileOutputStream fileOutputStream = new FileOutputStream("D:\\jdk17.zip");
// 创建缓冲数组
byte[] b = new byte[1024];
int len;
while ((len = fileInputStream.read(b)) != -1){
// 写入数据
fileOutputStream.write(b,0,len);
}
// 关流
fileOutputStream.close();
fileInputStream.close();
}
5 读取内存的流
public static void main(String[] args) throws IOException {
// String str = "abcdefg";
// // 创建读取字符串的流
// StringReader stringReader = new StringReader(str);
//
// // 循环读取内容
// char[] cs = new char[3];
// int len;
// while ((len = stringReader.read(cs)) != -1){
// System.out.print(new String(cs,0,len));
// }
//
// // 关流
// stringReader.close();
StringWriter stringWriter = new StringWriter();
stringWriter.write("abc");
// 关流
stringWriter.close();
// ByteArrayOutputStream
// ByteArrayInputStream
// CharArrayWriter
// CharArrayReader
}
6 转换流
public static void main(String[] args) throws IOException {
// 转换流就是可以将字节流转换成字符流
// 底层实际上是依靠传入的字节流来写出数据
// 输出流
// OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("E:\\abc.txt"));
// // 写出数据
// outputStreamWriter.write("abc");
//
// // 关流
// outputStreamWriter.close();
// 输入流
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("E:\\abc.txt"));
char[] chars = new char[3];
inputStreamReader.read(chars);
System.out.println(chars);
// 关流
inputStreamReader.close();
}
7 系统流
| System.out | 系统输出流 |
|---|---|
| System.in | 系统输入流 |
| System.err | 系统错误流 |
public static void main(String[] args) throws IOException {
// 一次读取一个字符
// System.in 字节输入流
// int read = System.in.read();
// // System.out 字节输出流
// System.out.println((char) read);
// // System.err 字节输出流
// System.err.println((char) read);
for (int i = 0; i < 10000; i++) {
System.out.println('a');
System.err.println('a');
}
}
- 课堂练习:用已知的流从控制台读取一行数据
// 用已知的流从控制台读取一行数据
// BufferedReader 能够读取一行
// System.in 从控制台获取数据
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
// 读取一行数据
String line = bufferedReader.readLine();
System.out.println(line);
// 关流
bufferedReader.close();
Scanner为什么不关流?
public static void main(String[] args) throws IOException {
// in是一个静态的流对象
// 意味着多个Scanner用的是同一个in
// 一个被关了,其他地方都不可以使用了
Scanner scanner = new Scanner(System.in);
String next = scanner.next();
System.out.println(next);
}
8 打印流
PrintWriter和PrintStream
只有输出流,没有输入流l
PrintWriter属于字符输出流
PrintStream属于字节输出流
public static void main(String[] args) throws IOException {
PrintStream printStream = new PrintStream("a.txt");
// 输出
printStream.write("尚马".getBytes());
// 输出并换行
printStream.println("教育");
printStream.print("谷丰硕");
// 关流
printStream.close();
PrintWriter printWriter = new PrintWriter("b.txt");
printWriter.println("cbd");
printWriter.write("abc");
// 关流
printWriter.close();
}
9 合并流
public static void main(String[] args) throws IOException {
// 创建要合并的流
InputStream in1 = new FileInputStream("E:\\a.txt");
InputStream in2 = new FileInputStream("E:\\b.txt");
InputStream in3 = new FileInputStream("E:\\c.txt");
InputStream in4 = new FileInputStream("E:\\d.txt");
// 创建向量
Vector<InputStream> vector = new Vector<>();
vector.add(in1);
vector.add(in2);
vector.add(in3);
vector.add(in4);
// 合并流
SequenceInputStream sequenceInputStream = new SequenceInputStream(vector.elements());
// 创建输出流
FileOutputStream fileOutputStream = new FileOutputStream("E:\\e.txt");
// 创建缓冲数组
byte[] bs = new byte[20];
// 读取到的实际个数
int len;
while ((len = sequenceInputStream.read(bs)) != -1){
fileOutputStream.write(bs,0,len);
}
// 关流
fileOutputStream.close();
sequenceInputStream.close();
}
10 随机获取流
mode:
- r 读
- rw 读写
- rws 读写并写入硬盘
- rwd 读写并写入硬盘,同步保存
public static void main(String[] args) throws IOException {
// 创建随机获取流对象 双向流
RandomAccessFile randomAccessFile = new RandomAccessFile("c.txt","rw");
// 向文件中写入123
// 底层把操作文件看作一个字节数组,索引从0开始
randomAccessFile.write("123".getBytes());
System.out.println((char)randomAccessFile.read());
// 可以指定索引
randomAccessFile.seek(0);
// 已经指定了索引是0,读取的时候从头读取 结果是1
System.out.println((char)randomAccessFile.read());
// 设置跳过n个索引
randomAccessFile.skipBytes(5);
System.out.println((char)randomAccessFile.read());
// 关流
randomAccessFile.close();
}
11 序列化和反序列化流
序列化:将对象以及其中的信息转换成字节进行完成保存
反序列化:将存储的字节数组取出来还原成对应的对象
如果一个对象想要被序列化,对应的类要实现Serializable接口
被static修饰的属性称之为静态变量,属性类不属于对象,所以不能序列化,因为没有意义
被transient修饰的属性强制性不能序列化
serialVersionUID: 版本号
每一个类在实现Serializable接口之后这个类会自动产生一个版本号。如果这个版本号没有手动指定,那么java在编译的时候会根据当前类中的属性和方法自动计算,也就意味着当类中的属性和方法产生变动的时候,版本号也会重新计算。序列化的时候版本号会随着对象一起序列化出去。当对象反序列化的时候,会拿着原来的版本号和当前类中的版本号进行比较。如果版本号一致,则允许反序列,否则抛出异常InvalidClassException
Peson类
package cn.javasm.demo;
import java.io.Serializable;
/**
* @className: Person
* @description:
* @author: gfs
* @date: 2025/7/11 17:05
* @version: 0.1
* @since: jdk17
*/
public class Person implements Serializable {
// 手动指定版本号
private static final long serialVersionUID = 4654757657546346L;
private String name;
private int age;
private String address;
static String classroom;
private transient double height;
private String gender;
public static String getClassroom() {
return classroom;
}
public static void setClassroom(String classroom) {
Person.classroom = classroom;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
", height=" + height +
", gender='" + gender + '\'' +
'}';
}
}
测试方法
public static void main(String[] args) throws IOException, ClassNotFoundException {
demo2();
}
private static void demo2() throws IOException, ClassNotFoundException {
// 反序列化
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("p.data"));
// 读取对象
Person person = (Person) objectInputStream.readObject();
System.out.println(person);
// 关流
objectInputStream.close();
}
private static void demo1() throws IOException {
Person person = new Person();
person.setName("周杰伦");
person.setAge(45);
person.setAddress("台湾");
person.classroom = "三年二班";
person.setHeight(175.4);
// 一个对象要想序列化,这个对象对应的类必须实现Serializable接口
// 序列化
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("p.data"));
// 保存对象
objectOutputStream.writeObject(person);
// 关流
objectOutputStream.close();
}
12 Properties
Properties是Hashtable的子类:同步线程安全的,key和value都不能是null,key和value的类型都是字符串
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
// 添加数据
properties.setProperty("name","胡理想");
properties.setProperty("age","23");
properties.setProperty("gender","male");
// 持久化到硬盘中
// 存储数据
properties.store(new FileOutputStream("person.properties"),"this is a comment");
// 读取数据
properties.load(new FileInputStream("person.properties"));
// 根据key获取value
String name = properties.getProperty("name");
System.out.println(name);
System.out.println(properties);
}

浙公网安备 33010602011771号