一 缓冲流
1.1 概述
缓冲流,也叫高效流,是对4个基本的FileXxx 流的增强,所以也是4个流,按照数据类型分类:
-
字节缓冲流: BufferedInputStream , BufferedOutputStream
-
字符缓冲流: BufferedReader , BufferedWriter
1.2 字节缓冲流
构造方法
public BufferedInputStream(InputStream in)
:创建一个 新的缓冲输入流。
public BufferedOutputStream(OutputStream out)
: 创建一个新的缓冲输出流。 参数OutputStream out:字节输出流
我们可以传递FileOutputStream缓冲流会给FileOutputStream增加缓冲区,提高FileOutputStream的写入效率,int size:指定缓冲流内部缓冲区的大小
使用步骤
1,创建FileOutputStream对象,构造方法指定绑定要输出的目的地
2,创建BufferedOutputStream对象,构造方法传递FileOutputStream对象,提高FileOutputStream效率。
3,使用BufferedOutputStream对象中的write,把数据写入到内部缓冲区
4,使用BufferedOutputStream对象中的flush,把缓冲区的数据刷新到文件中。
5,释放资源,会先调用flush方法刷新数据,第4部可以省略
1.3 字符缓冲流
构造方法
public BufferedReader(Reader in)
:创建一个 新的缓冲输入流。
public BufferedWriter(Writer out)
: 创建一个新的缓冲输出流。
使用步骤:
1,创建FileInputStream对象,构造方法指定绑定要输出的目的地
2,创建BufferedInputStream对象,构造方法传递BufferedInputStream对象,提高BufferedInputStream效率。
3,使用BufferedInputStream对象中的read,读取文件
4,释放资源,会先调用flush方法刷新数据,第4部可以省略
特有方法
BufferedReader: public String readLine() : 读一行文字。
行的终止符号:通过下列字符之一即可认为某行终止:换行('\n')、回车('\r')
返回值:包含改行内容的字符串,不包括任何终止符,如果已经到达流末尾,则返回null
BufferedWriter: public void newLine() : 写一行行分隔符,由系统属性定义符号。
使用步骤:
1,创建字符缓冲输入流对象,构造方法中传递字符输入流
2,使用字符缓冲输入流对象中的额方法read/readline读取文本
3,释放资源
1.4 练习:文本排序
对文本的内容进行排序
`public class Test1215 {
public static void main(String[] args) throws IOException {
//1,创建一个HashMap集合对象,可以存储每行文本的序号;value:存储每行的文本
HashMap<String,String> map = new HashMap<>();
//2,创建字符缓冲流对象,构造方法中绑定字符输入流,文件路径
BufferedReader br = new BufferedReader(new FileReader("c:\\in.txt"));
//3,创建字符缓冲输入流,构造方法中绑定字符输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("c:\\out.txt"));
//4,使用字符缓冲输入流中的方法readline,逐行读取文本,创建一个字符line
String line;
//增强for循环,line不为空
while( (line = br.readLine())!=null){
//5,对读取到的文本进行切割,获取行中的序号和文本内容
String[] arr = line.split("\\.");
//6.把切割好的序号和文本的内容存储到HashMap中,(key)序号是有序的,自动排序1.2.3...
map.put(arr[0],arr[1]);
}
//7,遍历HashMap集合,获取每一个键值对
for(String key:map.keySet()){
String value = map.get(key);
// 8,把每一个键值对,拼接为一个文本行
line = key +"."+ value;
//9,把拼接好的文本,使用字符缓冲输出流中的额方法write写入到文本中
bw.write(line);
bw.newLine();
}
//10,释放资源
bw.close();
br.close();
}
}`
二 转换流
2.1 字符编码
计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。按照某种规则,将字符存储到计算机中,称为编码 。
将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码 。
字符编码Character Encoding : 就是一套自然语言的字符与二进制数之间的对应规则。
字符集
字符集 Charset :也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。
计算机要准确的存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符 集有ASCII字符集、GBK字符集、Unicode字符集等。
win7 或者 win10 简体中文用的都是GBK字符集
Unicode字符集 :
Unicode编码系统为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码。它最多使用4个字节的数字来表达每个字母、符号,或者文字。有三种编码方案,UTF-8、UTF-16和UTF-32。
最为常用的UTF-8编码。 UTF-8编码,可以用来表示Unicode标准中任何字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。所以,我们开发Web应用,也要使用UTF-8编码。它使用一至四个字节为每个字符编码,编码规则: 1. 128个US-ASCII字符,只需一个字节编码。 2. 拉丁文等字符,需要二个字节编码。 3. 大部分常用字(含中文),使用三个字节编码。 4. 其他极少使用的Unicode辅助字符,使用四字节编码。
2.2 编码引出的问题
使用FileReader 读取项目中的文本文件。由于IDEA的设置,都是默认的UTF-8 编码,所以没有任何问题。但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码。
2.3 InputStreamReader类
转换流java.io.InputStreamReader ,是Reader的子类,是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。
构造方法
InputStreamReader(InputStream in)
: 创建一个使用默认字符集的字符流。
InputStreamReader(InputStream in, String charsetName)
: 创建一个指定字符集的字符流。
参数:InputStream in:读取文件中的字节
String charsetName:String charsetName
使用步骤:
1,创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称
2,使用OutputStreamWriter对象中的方法read,读取文件
3,释放资源
注意事项:构造方法中指定的编码名称要和文件的编码相同,否则乱码
2.4 OutputStreamWriter类
转换流java.io.OutputStreamWriter ,是Writer的子类(write里面的方法都可以使用),是从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。
OutputStreamWriter(OutputStream out)
: 创建一个使用默认字符集的字符流。
OutputStreamWriter(OutputStream out, String charsetName)
: 创建一个指定字符集的字符流。
参数 OutputStream out:字节输出流,可以用来写转换后的字节到文件中
String charsetName:指定的编码表名称,不区分大小写,不指定默认UTF-8
使用步骤:
1,创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称
2,使用OutputStreamWriter对象中的方法write,把字符转换为字节存储缓冲区中(编码)
3,使用OutputStreamWriter对象中的的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节写字节的过程)
4,释放资源
三 序列化
3.1 概述
Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据、对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象 **
3.2 ObjectOutputStream类
java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。
构造方法 public ObjectOutputStream(OutputStream out)
: 创建一个指定OutputStream的ObjectOutputStream
注意事项:
序列化反序列化的时候,会抛出NotSertialzableEexception没有序列化异常,需要用过java.io.Serializable接口以启动其序列化功能,给类添加一个标记。
Serializable 接口也叫标记型接口,没有就会抛出异常
3.3 ObjectInputStream类
ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
构造方法 public ObjectInputStream(InputStream in)
: 创建一个指定InputStream的ObjectInputStream。
InputStream in:字节输入流
特有的成员方法:Object readObject()从ObjectInputStream读取对象
使用步骤:
1,创建ObjectInputStream对象,构造方法中传递字节输入流
2,使用ObjectInputStream对象中的方法readObject读取保存的文件
3,释放资源
注意:readObject方法声明可能抛出ClassNotFoundEexception(文件找不到),当不存在对象的class文件时抛出异常。
反序列化的前提:
1,类必须实现Serializable
2,必须存在类对应的class
另外,当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException 异常。
发生这个异常的原因如下:
-
该类的序列版本号与从流中读取的类描述符的版本号不匹配
-
该类包含未知数据类型
-
该类没有可访问的无参数构造方法 ** 解决办法:用final修饰serialVersionUID 使用serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配,设定序列号。
3.4 transient关键字
static关键字:(静态关键字):静态优先于非静态加载到内存中,被静态static修饰的成员变量不能被序列化,序列化的都是对象。
transient关键字(瞬态关键字):被transient修饰的成员变量,不能被序列化。
四 打印流
java.io.PrintStream :打印流
PrintStream特点:
1,只负责数据的输出,不负责数据的读取
2,与其他输出流不同,PrintStream永远不会抛出IOException
3,有特有的方法,print 方法和println
构造方法:
PrintStream(File file)
:输出目的地是一个文件
PrintStream(OutputStream out)
:输出目的地是一个字节输出流
PrintStream(String filaname)
:输出目的地是一个文件路径
PrintStream extends OutputStream 继承父类的成员方法
注意事项:
1,如果使用继承自父类的write方法写数据,那么查看数据的时候回查询编码表
2,如果使用自己特有的方法print 方法和println方法写数据,写的数据原样输出