1.IO流的分类
按处理数据单位不同分为字节流和字符流。
字节流:每次读取(写出)一个字节,当传输的资源文件有中文时,就会出现乱码。
字符流:每次读取(写出)两个字节,有中文时,使用该流就可以正确传输显示中文。
1字符 = 2字节; 1字节(byte) = 8位(bit); 一个汉字占两个字节长度。
字节流和字符流的区别
1.字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的;而字符流在操作时使用了缓冲区,通过缓冲区再操作文件
2.字节流一般用来处理图像,视频,以及PPT,Word类型的文件。字符流一般用于处理纯文本类型的文件,如TXT文件等。字节流可以用来处理纯文本文件,但是字符流不能用于处理图像视频等非文本类型的文件
2.IO相关类结构
IO类主要有四个基类
字节输入流InputStream
java.io 包下所有的字节输入流都继承自 InputStream,并且实现了其中的方法。InputStream 中提供的主要数据操作方法如下:
int read():从输入流中读取一个字节的二进制数据。
int read(byte[] b):将多个字节读到数组中,填满整个数组。
int read(byte[] b, int off, int len):从输入流中读取长度为 len 的数据,从数组 b 中下标为 off 的位置开始放置读入的数据,读完返回读取的字节数。
void close():关闭数据流。
int available():返回目前可以从数据流中读取的字节数(但实际的读操作所读得的字节数可能大于该返回值)。
long skip(long l):跳过数据流中指定数量的字节不读取,返回值表示实际跳过的字节数。
字节输出流OutputStream
与字节输入流类似,java.io 包下所有字节输出流大多是从抽象类 OutputStream 继承而来的。OutputStream 提供的主要数据操作方法:
void write(int i):将字节 i 写入到数据流中,它只输出所读入参数的最低 8 位,该方法是抽象方法,需要在其输出流子类中加以实现,然后才能使用。
void write(byte[] b):将数组 b 中的全部 b.length 个字节写入数据流。
void write(byte[] b, int off, int len):将数组 b 中从下标 off 开始的 len 个字节写入数据流。元素 b[off] 是此操作写入的第一个字节,b[off + len - 1] 是此操作写入的最后一个字节。
void close():关闭输出流。
void flush():刷新此输出流并强制写出所有缓冲的输出字节。
为了加快数据传输速度,提高数据输出效率,又是输出数据流会在提交数据之前把所要输出的数据先暂时保存在内存缓冲区中,然后成批进行输出,每次传输过程都以某特定数据长度为单位进行传输,在这种方式下,数据的末尾一般都会有一部分数据由于数量不够一个批次,而存留在缓冲区里,调用 flush() 方法可以将这部分数据强制提交。
字节流代码演示
这个示例是copy文件,把一个文件的内容copy到另一个文件。既用到了字节输入流也用到了字节输出流。
package com.mashibing.Stream;
import java.io.*;
/**
* @author: ggf
* @create: 2020-04-22 20:02
*/
public class CopyFile {
public static void main(String[] args) {
//定义源数据文件
File src = new File("abc.txt");
//定义目的数据文件
File dest = new File("aaa.txt");
//创建输入流对象
InputStream inputStream = null;
//创建输出流对象
OutputStream outputStream = null;
try {
inputStream = new FileInputStream(src);
outputStream = new FileOutputStream(dest);
//带缓存的输入输出方式
byte[] buffer = new byte[1024];
int length = 0;
//完成数据传输的过程
while((length = inputStream.read(buffer))!=-1){
outputStream.write(buffer);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字符输入流Reader
Reader是所有的输入字符流的父类,它是一个抽象类。
- CharReader和SringReader是两种基本的介质流,它们分别将Char数组、String中读取数据。PipedReader 是从与其它线程共用的管道中读取数据。
BufferedReader很明显是一个装饰器,它和其他子类负责装饰其他Reader对象。 - FilterReader是所有自定义具体装饰流的父类,其子类PushBackReader对Reader对象进行装饰,会增加一个行号。
- InputStreamReader是其中最重要的一个,用来在字节输入流和字符输入流之间作为中介,可以将字节输入流转换为字符输入流。FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。
Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。
字符输出流
Writer是所有的输出字符流的父类,它是一个抽象类。
- CharWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。
- PipedWriter 是向与其它线程共用的管道中写入数据。
- BufferedWriter 是一个装饰器为Writer 提供缓冲功能。
- PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。
- OutputStreamWriter是其中最重要的一个,用来在字节输出流和字符输出流之间作为中介,可以将字节输出流转换为字符输出流。FileWriter 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将OutputStream转变为Writer 的方法。
Writer 中各个类的用途和使用方法基本和OutputStream 中的类使用一致。
字符流代码演示
这个示例是接收控制台上的输入作为字符输入流接收,然后用字符输出流打印出来。最后用exit结束。还是很好地解释了这个字符输入输出流
package com.mashibing.exercise;
import java.io.*;
/**
* @author: ggf
* @create: 2020-04-28 15:34
*/
public class ExitTest {
public static void main(String[] args) {
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(System.out);
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
try {
String str = "";
while (!str.equals("exit")) {
str = bufferedReader.readLine();
bufferedWriter.write(str);
bufferedWriter.flush();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
inputStreamReader.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
outputStreamWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}