缓冲流
作用:对原始流进行包装,以提高原始流读写数据的性能
原理:字节缓冲输入流自带了 8 KB 缓冲池;字节缓冲输出流也自带了 8 KB 缓冲池
字节缓冲流
import java.io.*;
public class Test {
public static void main(String[] args) throws Exception {
try (
InputStream inputStream = new FileInputStream("E:/Desktop/photo.jpg");
// 1. 定义一个字节缓冲输入流包装原始的字节输入流
InputStream bis = new BufferedInputStream(inputStream);
OutputStream outputStream = new FileOutputStream("E:/Desktop/aaa/photo.jpg");
// 2. 定义一个字节缓冲输出流包装原始的字节输出流
OutputStream bos = new BufferedOutputStream(outputStream);
) {
// 3. 创建一个字节数组,负责转移字节数据
byte[] buffer = new byte[1024]; // 1KB
// 4. 从字节输入流中读取字节数据,写出去到字节输出流中,读多少写多少
int len; // 记住每次读取了多少个字节
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
System.out.println("复制成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
字符缓冲流
- 字符缓冲输入流
import java.awt.*;
import java.io.*;
public class Test {
public static void main(String[] args) throws Exception {
try (
Reader fr = new FileReader("E:/Desktop/temp.txt");
// 创建一个字符缓冲输入流包装原始的字符输入流
BufferedReader br = new BufferedReader(fr);
) {
// char[] buffer = new char[3];
// int len;
// while ((len = br.read(buffer)) != -1) {
// System.out.println(new String(buffer, 0, len));
// }
// BufferedReader 类为 Reader 类新增了一个功能,想要使用这个功能的话,请不要使用多态写法,直接写 BufferedReader br = ...
// System.out.println(br.readLine()); // 每调用一次,就从文本文件里面读取一行的数据给我们
// System.out.println(br.readLine());
// System.out.println(br.readLine());
String line; // 记住每次读取的行数
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 字符缓冲输出流
import java.io.*;
public class Test {
public static void main(String[] args) throws Exception {
try (
Writer fw = new FileWriter("E:/Desktop/temp.txt");
// 创建一个字符缓冲输出流包装原始的字符输出流
BufferedWriter bw = new BufferedWriter(fw);
) {
bw.write('a');
bw.write(97);
bw.write('啊');
bw.newLine(); // bw.write("\r\n");
bw.write("我们都是追梦人");
bw.newLine(); // bw.write("\r\n");
} catch (Exception e) {
e.printStackTrace();
}
}
}
转换流
字符输入转换流
本质:先获取文件的原始字节流,再将其按照真实的字符集编码转换成字符输入流,这样字符输入流中的字符就不会乱码
import java.io.*;
public class Test {
public static void main(String[] args) {
try (
// 1. 得到文件的原始字节流(GBK的字节流形式)
InputStream is = new FileInputStream("E:/Desktop/temp.txt");
// 2. 把原始的字节输入流按照指定的字符集编码转换成字符输入流
Reader isr = new InputStreamReader(is, "GBK");
//3. 把字符输入流包装成缓冲字符输入流
BufferedReader br = new BufferedReader(isr);
) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
字符输出转换流
需求:当我们想要控制写出去的字符使用特定的字符集编码,改怎么办?
方法一:调用 String 提供的 getBytes 方法解决———— byte[ ] bytes = "abc".getBytes("GBK");
方法二:使用 “字符输出转换流”
import java.io.*;
public class Test {
public static void main(String[] args) {
try (
// 1. 创建一个文件字节输出流
OutputStream os = new FileOutputStream("E:/Desktop/temp.txt");
// 2. 把原始的字节输出流,按照指定的字符集编码转换成字符输出转换流
Writer osw = new OutputStreamWriter(os, "utf-8");
//3. 把字符输入流包装成缓冲字符输入流
BufferedWriter bw = new BufferedWriter(osw);
) {
bw.write("我们都是追梦人");
bw.write("abcdefg");
} catch (Exception e) {
e.printStackTrace();
}
}
}
打印流
作用:打印流可以更方便、更高效的打印数据出去,能实现打印什么出去就是什么出去
- PrintStream ( 字节流下的实现类 )
- PrintWriter ( 字符流下的实现类 )
两者的区别:
- 打印数据的功能上是一模一样的:都是方便使用,性能高效(实际开发中,主要是用这个功能而已)
- PrintStream 继承自"字节输出流" OutputStream,因此支持写字节数据的方法
- PrintWriter 继承自"字符输出流" Writer,因此支持写字符数据出去
PrintStream
import java.io.PrintStream;
import java.nio.charset.Charset;
public class Test {
public static void main(String[] args) {
try (
// 1. 创建一个打印流管道
PrintStream ps = new PrintStream("E:/Desktop/temp.txt", Charset.forName("GBK"));
) {
ps.println(78); // 78
ps.println('a'); // a
ps.println("我们都是追梦人"); // 我们都是追梦人
ps.println(true); // true
ps.println(66.8); // 66.8
ps.write(97); // a
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
PrintWriter
import java.io.FileOutputStream;
import java.io.PrintWriter;
public class Test {
public static void main(String[] args) {
try (
// 1. 创建一个打印流管道(高级流无法开启追加的true,但是底层流(低级流)可以)
PrintWriter ps = new PrintWriter(new FileOutputStream("E:/Desktop/temp.txt",true));
) {
ps.println(78); // 78
ps.println('a'); // a
ps.println("我们都是追梦人"); // 我们都是追梦人
ps.println(true); // true
ps.println(66.8); // 66.8
ps.write(97); // a
ps.write("我们都是追梦人"); // 我们都是追梦人
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
打印流的应用——输出重定向
import java.io.PrintStream;
public class Test {
public static void main(String[] args) {
try (
PrintStream ps = new PrintStream("E:/Desktop/temp.txt");
) {
// 把系统默认的打印流对象修改成自己设置的打印流对象
System.setOut(ps);
System.out.println("abc");
System.out.println("我不吃");
} catch (Exception e) {
e.printStackTrace();
}
}
}
数据流
- DataOutputStream(数据输出流)
- fa
// 数据输出流
import java.io.DataOutputStream;
import java.io.FileOutputStream;
public class Test {
public static void main(String[] args) {
try (
// 1. 创建一个数据输出流包装低级的字节输出流
DataOutputStream dos =
new DataOutputStream(new FileOutputStream("E:/Desktop/temp.txt"))
) {
dos.writeInt(97);
dos.writeDouble(8.7);
dos.writeBoolean(true);
dos.writeUTF("我们都是追梦人");
// 这些数据都包含了类型的,并不是为了给我们看,而是方便读取数据和它的类型
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 数据输入流
import java.io.*;
public class Test {
public static void main(String[] args) {
try (
// 1. 创建一个数据输入流包装低级的字节输入流
DataInputStream dis =
new DataInputStream(new FileInputStream("E:/Desktop/temp.txt"))
) {
// 什么数据类型输入的,就以什么数据类型读取
System.out.println(dis.readInt());
System.out.println(dis.readDouble());
System.out.println(dis.readBoolean());
System.out.println(dis.readUTF());
// 运行结果
// 97
// 8.7
// true
// 我们都是追梦人
} catch (Exception e) {
e.printStackTrace();
}
}
}
序列化流
对象序列号:把 Java 对象写入到文件中去(或传播到网络中)
对象反序列化:把文件中的 Java 对象读取出来
ObjectOutputStream (对象字节输出流):可以把 Java 对象进行序列化——把 Java 对象存到文件中
ObjectInputStream(对象字节输入流):可以把 Java 对象进行反序列化——把文件中的 Java 对象读取出来
序列化
import java.io.*;
public class Test {
public static void main(String[] args) {
try (
// 2. 创建一个对象字节输出流包装原始的字节输出流
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream("E:/Desktop/temp.txt"))
) {
// 1. 创建一个 Java 对象
User u = new User("admin", "Jack", 32, "123456");
// 3. 序列化对象到文件中去
oos.writeObject(u);
System.out.println("序列化对象成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 注意!如果需要序列化某个对象,就必须为它的类接上一个"序列化接口" ... implements Serializable
class User implements Serializable{
private String loginName;
private String userName;
private int age;
private String password;
public User() {
}
public User(String loginName, String userName, int age, String password) {
this.loginName = loginName;
this.userName = userName;
this.age = age;
this.password = password;
}
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
反序列化
import java.io.*;
public class Test {
public static void main(String[] args) {
try (
// 1. 创建一个对象字节输入流包装原始的字节输入流
ObjectInputStream ois =
new ObjectInputStream(new FileInputStream("E:/Desktop/temp.txt"))
) {
User obj = (User) ois.readObject(); // 反序列化
System.out.println(obj); // 输出:User{loginName='admin', userName='Jack', age=32, password='123456'}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 注意!如果需要序列化某个对象,就必须为它的类接上一个"序列化接口" ... implements Serializable
class User implements Serializable {
private String loginName;
private String userName;
private int age;
// 使用 transient 后,这个成员变量将不参与序列化
// private transient String password;
private String password;
public User() {
}
public User(String loginName, String userName, int age, String password) {
this.loginName = loginName;
this.userName = userName;
this.age = age;
this.password = password;
}
@Override
public String toString() {
return "User{" +
"loginName='" + loginName + '\'' +
", userName='" + userName + '\'' +
", age=" + age +
", password='" + password + '\'' +
'}';
}
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
附:如果要一次序列化多个对象,怎么办?
解决办法:用一个 ArrayList 集合存储多个对象,然后直接对集合进行序列化即可(注意!ArrayList 集合已经实现了序列化接口,我们不需要画蛇添足)
IO 框架
什么是框架
解决某类问题,编写的一套类、接口等,可以理解为一个半成品,大多框架都是第三方研发的
好处:在框架的基础上开发,可以得到优秀的软件架构,并能提供开发效率
框架的形式:一般是把类、接口等编译成 class 形式,再压缩成一个 .jar 结尾的文件发行出去
什么是 IO 框架
封装了 Java 提供的对文件、数据进行操作的代码,对外提供了更简单的方式来对文件进行操作,对数据进行读写等
Commons-io
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
public class Test {
public static void main(String[] args) throws Exception {
// 第三方
FileUtils.copyFile(new File("E:/Desktop/temp.txt"), new File("E:/Desktop/temp2.txt"));
FileUtils.copyDirectory(new File("E:/Desktop/MyDirectory"), (new File("E:/Desktop/MyDirectory2"));
FileUtils.deleteDirectory(new File("E:/Desktop/MyDirectory2"));
// Java 官方,也提供了很多的原生的代码方法,让我们用一行代码完成很多事情
Files.copy(Path.of("E:/Desktop/源文件路径"), Path.of("E:/Desktop/目标位置")); // copy文件内容
System.out.println(Files.readString(Path.of("E:/Desktop/文件路径"))); // 读取文件内容,并输出
}
}