文章目录
- 一、相对论理解IO流
- 二、汉语文学理解流
- 三、图解IO流
- 四、俩亲爹InputStream和OutputStream
- 五、FileInputStream字节流读取文件
- 六、FileOutputStream字节流写入文件
- 七、buff缓冲复制文件
- 1. 例一(无buff)
- 2. 例二(有buff)
- 八、buffered字节缓冲流和装饰设计模式
- 九、FileReader和FileWriter,俩专门来搞txt文件的
- 十、BufferedReader和BufferedWriter
- 十一、一次性讲解剩余的N个流(扩展课)Java里那些极其骚的IO流
- 十二、Apache Common IO
- 1. 例一
- 2. 例二(arrayList的妙用)
- 十三、补充
- 十四、内容出处
一、相对论理解IO流
官方文档
不仅是水,数据也是如此。例如,你发了一个视频给你的朋友,数据就从你的电脑上流通到了ta的电脑上,这个过程就叫数据流。
二、汉语文学理解流
为什么中国人用”流"这个字,而外国人用"stream"来代替?
这个字的偏旁是三点水,所以古人说的流一定跟水有关。可以引申为数据在流动时也像水一样流动
三、图解IO流
官方文档
当我们打开一个记事本读取里面的内容时,数据从本地存储设备流入记事本程序。因此,相对于记事本程序而言,数据是输入的;相对于本地存储设备而言,数据是输出的。
四、俩亲爹InputStream和OutputStream
Package java.io
重点关注这俩:
filechannel(文件通道):并发编程 现在可以先忽略
五、FileInputStream字节流读取文件
第一部分代码出处
菜鸟教程
① 字节流:以字节为单位去读和写,好处在于可以读写任何文件(图片、.mp3、.mp4等都可以化为字节)
② FileInputStream又称为字节流的原因:它是按照字节来读的
package com.practice.demo3;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
public class TestIo {
private final static int SIZE = 4096;
@Test
public void inputFile() throws IOException {
FileInputStream fileInputStream = new FileInputStream("file\\1.txt");
// System.out.println("------------该部分代码来自上述网页--------------------------");
/*
System.out.println("按字节读取, read()返回读取到的字节");
int by = 0;
// 如果读到文件末尾, 则会返回-1
while ((by = fileInputStream.read()) != -1){
System.out.println(by);
}
*/
/*
System.out.println("read(byte[] b)返回读取到的字节个数");
byte[] buf = new byte[30];
int len = fileInputStream.read(buf);
System.out.println(len);
System.out.println(Arrays.toString(buf));
System.out.println(new String(buf, 0, len));
*/
/*
System.out.println("创建一个字节数组");
int len = 0;
byte[] buf = new byte[SIZE];
while((len = fileInputStream.read(buf))!= -1){
System.out.println(new String(buf, 0, len));
}
*/
// System.out.println("---------------------------------------------------");
System.out.println("结合一下菜鸟教程的案例:");
int by;
while ((by = fileInputStream.read()) != -1){
System.out.print((char)by);
}
fileInputStream.close(); // 不用的话就把管子切断,节省内存
// 以上写法其实都更倾向于读取一个字节数组
}
}
六、FileOutputStream字节流写入文件
菜鸟教程
执行结果:
@Test
public void outputFile() throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("file\\2.txt");
// getBytes()作用:把字符串转换成字符数组
byte[] bytes = "Hello World!".getBytes();
// for(int i = 0; i < bytes.length; ++i){
// System.out.print((char)bytes[i]);
// }
// 第一次执行上述命令后2.txt就会被创建出来, 删除方式:右击2.txt -> Delete -> OK -> 左下角Do Refactor
// 把字符数组里的内容写入文件
for(int i = 0; i < bytes.length; ++i){
fileOutputStream.write(bytes[i]);
}
fileOutputStream.close();
}
七、buff缓冲复制文件
文件输入输出流还有一些用途,比如说像:文件拷贝(文本文件(.txt)、媒体文件(.mp3、mp4、图片)均可)
1. 例一(无buff)
① 图片大的话可能会卡
② 此时是一个字节一个字节地从源文件读取,并且一个字节一个字节地写入到目标文件中。这种方式由于每次只处理一个字节,导致频繁地进行磁盘I/O操作,效率非常低。
@Test
public void copyFileBase() throws IOException{
FileInputStream fileInputStream = new FileInputStream("file\\1.jpg");
FileOutputStream fileOutputStream = new FileOutputStream("file\\target.jpg");
int by;
while((by = fileInputStream.read()) != -1){
fileOutputStream.write(by);
}
fileInputStream.close();
fileOutputStream.close();
}
2. 例二(有buff)
代码使用了缓冲区(buffer),这是一个字节容器,用于在内存中暂存数据。缓冲区的大小在这里被设置为1024字节。这样,每次从源文件读取和写入目标文件时,都是按照缓冲区的大小来进行的,即每次操作都是1024字节。这大大减少了磁盘I/O操作的次数,因为每次操作都处理更多的数据,从而显著提高了文件复制的速度。
当调用 fileInputStream.read(buff) 方法时,它会尝试填充整个缓冲区(最多1024字节),然后返回实际读取的字节数。这个字节数可能小于1024,比如在文件的最后部分。然后,fileOutputStream.write(buff, 0, by) 方法将这些字节写入目标文件。这个过程会一直重复,直到文件结束(即 read 方法返回-1)。
可以理解为搬运箱子,之前是一个人搬一个箱子,突然来了个大力士,一次性可以搬10个箱子。
总结来说,使用缓冲区是处理I/O操作时提高效率的常见做法,这在处理大文件时尤其重要。
@Test
public void copyFileBase2() throws IOException{
FileInputStream fileInputStream = new FileInputStream("File\\1.jpg");
FileOutputStream fileOutputStream = new FileOutputStream("File\\target2.jpg");
// 缓冲区
// 1024单位:字节
byte[] buff = new byte[1024];
int by;
while((by=fileInputStream.read(buff)) != -1){
fileOutputStream.write(buff, 0, by);
}
fileInputStream.close();
fileOutputStream.close();
}
八、buffered字节缓冲流和装饰设计模式
BufferedInputStream
① 之前用的是普通的字节流,然后手动创建缓冲区;现在直接用缓冲流,好处在于不需要自己手写缓冲区了。
② 装饰设计模式:把一个类当作一个函数的参数传进去
③ 这里默认的缓冲区大小是8192字节
@Test
public void bufferFileBase() throws IOException{
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("file\\1.txt"));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("file\\3.txt"));
int by;
while((by = bufferedInputStream.read()) != -1){
bufferedOutputStream.write(by);
}
bufferedInputStream.close();
bufferedOutputStream.close();
}
九、FileReader和FileWriter,俩专门来搞txt文件的
①
② FileReader
FileWriter
③ 用文件写学生管理系统,别再用FileInputStream和FileOutputStream了,应该用FileReader和FileWriter(它们针对于记事本这种输入输出设备文件)
④
但是我们可以从源码发现,FileReader和FileWriter的原理其实还是FileInputStream和FileOutputStream,只不过它俩可以使代码看起来更简洁一点。
@Test
public void fileReaderTest() throws IOException{
FileReader fileReader = new FileReader("file\\1.txt");
int ch;
while((ch = fileReader.read()) != -1){
// 可以把ln删掉
System.out.print((char)ch);
}
fileReader.close();
}
@Test
public void fileWriterTest() throws IOException{
FileWriter fileWriter = new FileWriter("file\\4.txt");
fileWriter.write("hello world!");
fileWriter.close();
}
十、BufferedReader和BufferedWriter
BufferedReader
BufferedWriter
① 进一步补充:用文件写学生管理系统,BufferedReader和BufferedWriter比FileReader和FileWriter速度快。
② 除此之外,BufferedWriter里有一个newLine()方法,可以根据不同的系统生成换行符(因为不同的系统换行符可能不同),所以更推荐用它去写入文件;BuffertedReader里有一个readLine()方法,可以按行读取字符
③ 但实际工作可能不太用这些
@Test
public void bufferedReaderTest() throws IOException{
BufferedReader bufferedReader = new BufferedReader(new FileReader("file\\2.txt"));
// 因为是字符流所以用String
// 之前用int那种实际是有问题的
String str;
while ((str = bufferedReader.readLine()) != null){
// 这个时候就可以加ln了
System.out.println(str);
}
bufferedReader.close();
}
@Test
public void bufferedWriterTest() throws IOException{
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("file\\5.txt"));
bufferedWriter.write("hhhhhhhh");
bufferedWriter.newLine();
bufferedWriter.write("ffffffff");
bufferedWriter.close();
}
十一、一次性讲解剩余的N个流(扩展课)Java里那些极其骚的IO流
① 借助它们可以用字节流操作字符流。但是要注意文件得是文本文件(因为涉及到操作字符流)
转换流InputStreamReader
转换流OutputStreamWriter
② 对象输入输出流:把一个对象写入文件,传的参数是一个Object对象
③ 存取成员变量(成员数据)
④ 打印流:存一个小的东西作为字符串输出
⑤ 输入输出流:System.out.println
在上述PrintStream里
⑥ 控制台
⑦ 多线程管道流(写底层用的,平时用得不多):多线程用的,多线程管道输入。这个流需要一个线程控制它去读,一个线程控制它去写,跟打电话一样。
Channel就是一个信道,和管道有区别。它们都跟并发有关,性能很高。
⑧
⑨
⑩ 可以理解为装货卸货。货多的时候就算用缓冲流也依然很慢。ByteArrayOutputStream这个类在创建时会自动创建一个Byte[]类型的缓冲区,写入的时候先把所有东西丢到缓冲区,最后再把所有东西一次性扔到另一个文件里
⑪ 跟上面的类似,只不过这里存的是char
⑫ 网上那种多线程下载跟这个类似,它会把两个东西进行合并。例如创建2个文件input流时,它可以把2个流合并,变成一个流。
另一个构造方法用到泛型(写框架会用到),可以提供多个流进行合并
⑬ I/O流都是从前向后,先后顺序读取。要想从文件任意处进行读写操作,字符流和字节流都做不到,只有RandomAccessFile可以实现。它虽然在java.io包里,但是它不属于流。
它可以用指针表明开始位置
或者直接用随机戳生成pos随机数
十二、Apache Common IO
apache公司自己写的io,可以帮助我们简化开发流程,非常实用
2.18jar包下载
2.18API文档
这里面有很多有意思的代码,例如:FileUtils。上节课手写的一些东西,这里几乎都有封装好可以直接拿来用的方法。
例子
1. 例一
@Test
public void writeTest() throws IOException{
File file = new File("file\\6.txt");
if(!file.exists()){
file.createNewFile();
}
FileUtils.writeLines(file, new ArrayList(Collections.singleton(("春风很柔,夏风很烈,秋风清爽,东风凛冽,你就是春夏秋冬的风"))), true);
}
2. 例二(arrayList的妙用)
需要往文件里写很多东西时就可以用它
writeLines方法涉及到泛型
package com.practice.demo3;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "name='" + name + '\'' +
", age=" + age
;
}
}
@Test
public void writeTest2() throws IOException{
File file = new File("file\\7.txt");
if(!file.exists()){
file.createNewFile();
}
ArrayList<Student> arrayList = new ArrayList<>();
// 第一个学生
arrayList.add(new Student("Tom", 12));
// 第二个学生
arrayList.add(new Student("Jerry", 14));
FileUtils.writeLines(file, arrayList, true);
}
十三、补充
File和IO Stream配合使用非常强
十四、内容出处
java