2.1 IO 分类
根据 数据的 流向 我们 分为:输入流 和 输出流
- 输入流:把数据 从 其他设备上 读取到 内存中的 流。
- 输出流:把数据 从 内存中 写出 到 其他 设备 上的 流。
根据 数据的 类型 分为:字节流 和 字符流。
- 字节流:以字节为 单位,读写数据的流。
- 字符流:以字符为 单位,读写数据的流。
如果 数据 是 字符数据,也就是 字符串,文字内容啥的。就属于 字符流。
如果是 字节数据,那就是 字节流。一般 字节数据 都是 各种文件。二进制那种的。
但 实际上,我们都知道 一切数据 都是 二进制的。只是 解析的不一样罢了。即 一切的 数据 在我们 Java 里 都可以 被当作 字节来处理。比如 文本内容、突破、视频 等等。而 字符流 只是 被 进行的 二次封装,更加 方便 我们 输入输出 字符数据。才发明的 字符流。
2.2 OutputStream 和 FileOutputStream
OutputStream 是一个 抽象类是 表示 字节输出流 的 所有类的 超类,将指定 的 字节信息 写出 到 目的地,它 定义了 字节输出流 的 基本 共性 功能 方法。
① close()
关闭和释放 输出流
② flush()
强制性 刷新 输出流,让其在 缓冲区里的 数据 直接 被写出。因为 正常情况下,都是 满了 缓冲区后 才会 进行 输出的。这样就会 出现假死现象。用 flush() 刷新下就好了。
③ write()
从指定的 字节 数组写入 len 个 字节,从 偏移量 off (起始位置) 开始 输出到 这个输出流。一旦 数据 被 输出到 某个 对象的 输出流里,这个数据 就会 流入 这个 对象!实现 写入 或 输出的功能。
抽象类 注定 是为了 真正有实际意义的 类 做铺垫的,比如 FileOutputStream 对 文件 进行 输出操作。 你像以前 我们也 接触过 socketOutputStream 这些其实 都是 实现类,使用起来 都 大同小异。
FileOutputStream 类 是 文件输出流,用于 将 数据 写出 到 文件。它是 OutputStream 非常经典的 实现类,它 有两个 构造方法。它 甚至 可以 在 该 文件 不存在的时候,创建该文件。然后 再 进行 输出操作。
FileOutputStream(File file)
创建文件输出流 以 写入的方式 指定 File 对象 那个 文件。FileOutputStream(String name)
创建文件输出流 以 写入的方式 指定 File 对象 那个 文件。
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("text.txt");
// 既然 是 写 字节,那么 就 建立 一个 字节数组呗。
byte[] bytes = "我是一个字符串".getBytes();
fileOutputStream.write(bytes,0,bytes.length);
}
字节嘛,当然 字符 也可以 输出了。本质都是字节!
剩下的 输出类,即使 你遇到了,也是 大同小异的。主要是 你得 理解 输入 输出的 逻辑。只要理解了 逻辑 和 使用的 步骤 基本上 就没问题了!
2.3 InputStream 和 FileInputStream
InputSream 抽象类 是表示 字节输入流 的 所有类的 超类,可以读取 字节信息 到 内存中。它 定义了 字节输入流 的 基本 共性 功能 方法。
close()
关闭 和 释放 输入流read()
从 输入流 读取数据的 下一个字节read(byte[] bytes)
从输入流 中 读取一些 字节数,并将 它们 存储 到 字节 数组 bytes 中。并且 还会 返回 读取 的 字节长度 len!这个 最常用!read(byte[] bytes,int off,int len)
从输入流 中 读取一部分 字节数,并将 它们 存储 到 字节 数组 bytes 中。并且 还会 返回 读取 的 字节长度 len!这个 最常用!
FileInputStream 是 InputStream 的一个 实现类,主要是 读取 文件的 数据 到 内存中。
FileInputStream(File file)
通过打开 文件,建立连接。来 获取 该 文件的 输入流。FileInputStream(String name)
通过打开 文件,建立连接。来 获取 该 文件的 输入流。
那么 FileinputStream 肯定 也有 read() 读的 方法呀,所以 获取到 文件的 输入流 后,我们 就可以 读取 该 文件的数据了。
FileInputStream fileInputStream = new FileInputStream("text.txt");
int len = fileInputStream.read(bytes);
System.out.println(new String(bytes,0,len));
常规并且稳定的写法:(自建缓冲区数组,while 循环慢慢的 来)
int len = 0;
FileInputStream fileInputStream = new FileInputStream("text.txt");
FileOutputStream fops = new FileOutputStream("text1.txt");
while((len = fileInputStream.read(bytes)) != -1){
fops.write(bytes,0,len);//bytes 1024 个字节
}
2.4 实现 复制 图片
既然 我们 已经 知道了 文件的 IO,那么 图片 也算是文件。我们只要 实现了 图片的 IO 不就相当于 学会了 所有文件的 IO 了嘛。确实是这样的!
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class 图片复制 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("C:\\Users\\muqua\\Desktop\\MuQuanyu\\个人信息\\头像.jpg");
FileOutputStream fos = new FileOutputStream("头像.jpg");
byte[] bytes = new byte[1024];
int len = 0;
while((len = fis.read(bytes)) != -1 ){
fos.write(bytes,0,len);
}
fos.close();
fis.close();
}
}
2.5 字符流
为什么有字符流呢?举一个 最 好理解的例子。我们的 汉字每一个 占 两个字节。英文和数字 每一个 占 一个字节。那么如果 我们 按照 字节流来读写的话 就不是那么的方便了。 可能 读 英文和 数字的时候 按照 一个字节一个字节 计算的, 但是到了 中文的时候 就得是 两个字节来计算。这 就会 很麻烦。而且 比如 你定义 一个 byte[10] 那么 你来回 读取 一段字符,不一定就 是按照 你想的那样读取的完整的。可能到了 汉字那里,就 按照 一个字节 读取了,那不就把 字 给砍了一半嘛。也就是出现了 乱码现象!!
2.6 Writer 和 FileWriter
Writer 抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法。
① write(unicode编码/ascii编码)
写入单个字符
② write(char[] cbuf)
写入一个 字符数组
③ write(char[] cbuf,int off,int len)
写入字符数组的 一部分,从 偏移 off 开始,写 len 个 字符。
④ write(String str)
写入字符串
⑤ write(String str,int off,int len)
写入字符串的 一部分,从 偏移 off 开始,写 len 个 字符。
⑥ flush()
刷新 该流 的 缓冲区
⑦ close()
关闭 和 释放 此 流,但最好是 将其 刷新 一下 再 关闭。
FileWriter 类 是 写出 字符到 文件里的 实现类,构造时使用系统默认的字符编码和默认字节缓冲区。
① FileWriter(File file)
创建 一个 新的 FileWriter,给定要 写入的 File 对象。
② FileWriter(String name)
创建 一个 新的 FileWriter,给定要 写入的 File 文件名称。
public static void main(String[] args) throws IOException {
Writer fw = new FileWriter("test.txt");
fw.write("我是一段 字符串!");
fw.flush();
fw.close();
}
2.7 Reader 和 FileReader
**Reader 抽象类 是 表示 用于 读取 字符流的 所有类的超类,可以 读取字符信息到 内存中。它 定义了 字符输入流的 基本 共性 功能方法。 **
close()
关闭 此 流 并 释放 与 此流 相关联 的 任何 系统 资源。
read()
从 输入流 读取的 一个 字符
read(char[])
从输入流 中 读取 一些字符,并把它们 存储到 字符数组里。
read(char[],int off,int len)
从输入流 中 读取 一部分字符,并把它们 存储到 字符数组里。
为啥 没有 存储到 String 里面的呢。主要是因为 数据的长度 不可定,我们可以用 字符数组来限制每次读取的字符长度,但是 String 是真心 不合适。所以 就没设计这种 方法。
FileReader 类 是 读取 字符文件的 类。构造 时 使用 系统默认的 字符编码 和 默认 字节缓冲区。
① FileReader(File file)
创建一个 新的 FileReader,给定 要 读取的 File 对象。
② FileReader(String name)
创建一个 新的 FileReader,给定 要 读取的 File 文件 名称。
import java.io.*;
public class WriterTest {
public static void main(String[] args) throws IOException {
Writer fw = new FileWriter("test.txt");
fw.write("我是一段 字符串!");
fw.flush();
fw.close();
Reader fr = new FileReader("test.txt");
char[] chars = new char[6];
int len = 0;
while((len = fr.read(chars)) != -1){
System.out.print(new String(chars,0,len));
}
fr.close();
}
}