一、缓冲流
- 缓冲流是在原始流的基础上进行包装,它们的作用是用来提高原始流读写数据的性能。
1、字节缓冲流
- 作用:提高字节流读写数据的性能
- 原理:字节缓冲输入流自带了8KB(8192)缓冲池;字节缓冲输出流也自带了8KB缓冲池。
- 总结:功能上和原始流并无很大变化,性能上提升了。
try (
InputStream is = new FileInputStream("io-app2/src/test01.txt");
// 1、定义一个字节缓冲输入流包装原始的字节输入流
InputStream bis = new BufferedInputStream(is);
OutputStream os = new FileOutputStream("io-app2/src/test01_bak.txt");
// 2、定义一个字节缓冲输出流包装原始的字节输出流
OutputStream bos = new BufferedOutputStream(os);
){
byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer)) != -1){
bos.write(buffer, 0, len);
}
System.out.println("复制完成!!");
} catch (Exception e) {
e.printStackTrace();
}
2、字符缓冲流
- 作用:提高字符流读写字符数据的性能
- 原理:字符缓冲输入流自带了8K(8192)的字符缓冲池;字符缓冲输出流也自带了8KB缓冲池。
try (
Reader fr = new FileReader("io-app2\\src\\test04.txt");
// 创建一个字符缓冲输入流包装原始的字符输入流
BufferedReader br = new BufferedReader(fr);
){
// char[] buffer = new char[3];
// int len;
// while ((len = br.read(buffer)) != -1){
// System.out.print(new String(buffer, 0, len));
// }
// System.out.println(br.readLine());
// 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();
}
try (
Writer fw = new FileWriter("io-app2/src/test05out.txt", true);
// 创建一个字符缓冲输出流管道包装原始的字符输出流
BufferedWriter bw = new BufferedWriter(fw);
){
bw.write('a');
bw.write(97);
bw.write('磊');
bw.newLine();
bw.write("我爱你中国abc");
bw.newLine();
} catch (Exception e) {
e.printStackTrace();
}
3、案例:字节缓冲流方式拷贝大文件
// 复制的视频路径
private static final String SRC_FILE = "D:\\resource\\线程池.avi";
// 复制到哪个目的地
private static final String DEST_FILE = "D:\\";
....................
// 缓冲流按照一个一个字节数组的形式复制,速度极快,推荐使用!
private static void copy() {
long startTime = System.currentTimeMillis();
try (
InputStream is = new FileInputStream(SRC_FILE);
BufferedInputStream bis = new BufferedInputStream(is, 64 * 1024);
OutputStream os = new FileOutputStream(DEST_FILE + "4.avi");
BufferedOutputStream bos = new BufferedOutputStream(os, 64 * 1024);
){
byte[] buffer = new byte[1024 * 64]; // 32KB
int len;
while ((len = bis.read(buffer)) != -1){
bos.write(buffer, 0, len);
}
}catch (Exception e){
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("缓冲流使用字节数组复制耗时:" + (endTime - startTime) / 1000.0 + "s");
}
二、转换流
- 引出问题:如果代码编码和被读取的文本文件的编码是不一致的,使用字符流读取文本文件时就会出现乱码!
1.字符输入转换流
-
作用:解决不同编码时,字符流读取文本内容乱码的问题。
-
解决思路:先获取文件的原始字节流,再将其按真实的字符集编码转成字符输入流,这样字符输入流中的字符就不乱码了。
try (
/**
* test06.txt内容
*
* 1床前明月光c
* 2疑是地上霜b
* 3低头思姑娘a
* abcde
*/
// 1、得到文件的原始字节流(GBK的字节流形式)
InputStream is = new FileInputStream("io-app2/src/test06.txt");//该文件的编码是GBK
// 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();
}
2.字符输出转换流
- 作用:可以控制写出去的字符使用什么字符集编码。
- 解决思路:获取字节输出流,再按照指定的字符集编码将其转换成字符输出流,以后写出去的字符就会用该字符集编码了
// 指定写出去的字符编码。
try (
// 1、创建一个文件字节输出流
OutputStream os = new FileOutputStream("io-app2/src/test07out.txt");
// 2、把原始的字节输出流,按照指定的字符集编码转换成字符输出转换流。
Writer osw = new OutputStreamWriter(os, "GBK");
// 3、把字符输出流包装成缓冲字符输出流
BufferedWriter bw = new BufferedWriter(osw);
){
bw.write("我是中国人abc");
bw.write("我爱你中国123");
} catch (Exception e) {
e.printStackTrace();
}
三、打印流
- 作用:打印流可以实现更方便、更高效的打印数据出去,能实现打印啥出去就是啥出去。
1、PrintStream提供的打印数据的方案
2、PrintWriter提供的打印数据的方案
try (
// 1、创建一个打印流管道
// PrintStream ps =
// new PrintStream("io-app2/src/itheima08.txt", Charset.forName("GBK"));
// PrintStream ps =
// new PrintStream("io-app2/src/itheima08.txt");
PrintWriter ps =
new PrintWriter(new FileOutputStream("io-app2/src/test08.txt", true));
){
ps.println(97);
ps.println('a');
ps.println("我爱你中国abc");
ps.println(true);
ps.println(99.5);
// ps.write(97); // 'a'
} catch (Exception e) {
e.printStackTrace();
}
3、打印流重定向
// 这2句会打印到控制台
System.out.println("老骥伏枥");
System.out.println("志在千里");
try ( PrintStream ps = new PrintStream("io-app2/src/test09.txt"); ){
// 把系统默认的打印流对象改成自己设置的打印流
System.setOut(ps);
// 这2句会打印到test09.txt文件中
System.out.println("烈士暮年");
System.out.println("壮心不已");
} catch (Exception e) {
e.printStackTrace();
}
PrintStream和PrintWriter的区别
- 打印数据的功能上是一模一样的:都是使用方便,性能高效(核心优势)
- PrintStream继承自字节输出流OutputStream,因此支持写字节数据的方法。
- PrintWriter继承自字符输出流Writer,因此支持写字符数据出去。
四、数据流
1、数据输出流
- 作用:允许把数据和其类型一并写出去。
try (
// 1、创建一个数据输出流包装低级的字节输出流
DataOutputStream dos =
new DataOutputStream(new FileOutputStream("io-app2/src/test10out.txt"));
){
dos.writeInt(97);
dos.writeDouble(99.5);
dos.writeBoolean(true);
dos.writeUTF("干得漂亮666!");
} catch (Exception e) {
e.printStackTrace();
}
2、数据输入流
- 作用:用于读取数据输出流写出去的数据。
try (
DataInputStream dis =
new DataInputStream(new FileInputStream("io-app2/src/test10out.txt"));
){
int i = dis.readInt();
System.out.println(i);
double d = dis.readDouble();
System.out.println(d);
boolean b = dis.readBoolean();
System.out.println(b);
String rs = dis.readUTF();
System.out.println(rs);
} catch (Exception e) {
e.printStackTrace();
}
五、序列化流
1、对象字节输出流
- 作用:可以把Java对象进行序列化:把Java对象存入到文件中去。
- 注意:对象如果要参与序列化,必须实现序列化接口(java.io.Serializable)
try (
// 2、创建一个对象字节输出流包装原始的字节 输出流。
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream("io-app2/src/test11out.txt"));
){
// 1、创建一个Java对象。
User u = new User("admin", "张三", 32, "666888xyz");
// 3、序列化对象到文件中去
oos.writeObject(u);
System.out.println("序列化对象成功!!");
} catch (Exception e) {
e.printStackTrace();
}
2、对象字节输入流
- 作用:可以把Java对象进行反序列化:把存储在文件中的Java对象读入到内存中来。
try (
// 1、创建一个对象字节输入流管道,包装 低级的字节输入流与源文件接通
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("io-app2/src/test11out.txt"));
){
User u = (User) ois.readObject();
System.out.println(u);
} catch (Exception e) {
e.printStackTrace();
}
User对象定义
public class User implements Serializable {
private String loginName;
private String userName;
private int age;
// transient 这个成员变量将不参与序列化。
private transient 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;
}
........//省略getter、setter
}
六、补充:IO框架
1、什么是 框架?
- 解决某类问题,编写的一套类、接口等,可以理解成一个半成品,大多框架都是第三方研发的。
- 好处:在框架的基础上开发,可以得到优秀的软件架构,并能提高开发效率。
- 框架的形式:一般是把类、接口等编译成class形式,再压缩成一个.jar结尾的文件发行出去。
2、什么是IO框架?
- 封装了Java提供的对文件、数据进行操作的代码,对外提供了更简单的方式来对文件进行操作,对数据进行读写等。
3、Commons-io
- Commons-io是apache开源基金组织提供的一组有关IO操作的小框架,目的是提高IO流的开发效率。
FileUtils.copyFile(new File("io-app2\\src\\test01.txt"), new File("io-app2/src/a.txt"));
FileUtils.copyDirectory(new File("D:\\resource\\私人珍藏"), new File("D:\\resource\\私人珍藏3"));
FileUtils.deleteDirectory(new File("D:\\resource\\私人珍藏3"));