1 IO流

1.1 概念

input:输入(读取)-----> 流:数据(字节/字符) -----> output:输出(写入)
输入:把硬盘中的数据,读取到内存中使用
输出:把内存中的数据,写入到硬盘中保存
内存:临时存储
硬盘:永久存储
1个字符 = 2个字节
1个字节=8个二进制位

顶层父类

输入流 输出流
字节流 字节输入流 InputStream 字节输出流 OutputStream
字符流 字符输入流 Reader 字符输出流 Writer

2 字节流

2.1 字节输出流OutputStream

它是一个抽象类

共性成员方法:

  1. public void close() :关闭此输出流并释放与此流相关联的任何系统资源。当完成流的操作时,必须调用此方法,释放系统资源。
  2. public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
  3. public void write(byte[] b) :将 b.length字节从指定的字节数组写入此输出流。
  4. public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
  5. public abstract void write(int b) :将指定的字节输出流。1次写1个字节。

2.1.1 文件字节输出流FileOutputStream

,extends OutputStream,把内存中的数据写入硬盘的文件中。

构造方法:创建一个 FileOutputStream 对象。根据参数传递的文件/文件路径,创建一个空文件。把 FileOutputStream 对象指向创建好的文件。

  1. FileOutputStream(String name):文件路径
  2. FileOutputStream(File file):文件

写入数据的原理(内存 —> 硬盘)

Java程序 —> JVM —>OS —> OS调用写数据的方法 —>把数据写入文件中

字节输出流的使用步骤

  1. 创建一个 FileOutputStream 对象,构造方法在传递写入数据的目的地
  2. 抵用 FileOutputStream 对象的write方法,把数据写入文件中
  3. 释放资源,清空流占用的内存,提高程序效率

把a写入a.txt文件

public abstract void write(int b)

 public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("a.txt");fos.write(97);fos.close();}

原理:写数据时会把十进制97转为二进制1100001‬,硬盘中存储的数据都是字节,1个字节等于8个比特位。文本编辑器在打开文件时会查询编码表,把字节转为字符表示,97—>a。


一次写入多个字节
public void write(byte[] b)
public void write(byte[] b, int off, int len) :把数组的一部分写入文件

 public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream(new File("b.txt"));byte[] a = {65,66,67,68,69};//ABCDEbyte[] b = {-65,-66,-67,68,69};//烤紻E//如果写的第一个字节是正数 显示会查ascii码表//如果是负数,第一个字节和第二个字节会组成一个中文显示 查询GBKfos.write(b);fos.write(a,1,2);//BCfos.close();}

使用String类的方法把字符串转换为字节数组。

 public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream(new File("b.txt"));byte[] b = "哈哈哈".getBytes();System.out.println(Arrays.toString(b));fos.write(b);fos.close();}

GBK:两个字节是一个中文
UTF8:三个字节是一个中文


数据的追加写和换行写
追加写的构造方法 append=true
FileOutputStream(String name, boolean append)
FileOutputStream(File file, boolean append)
换行:win【\r\n】mac【/n】linux【/r】

 public static void main(String[] args) throws IOException {//追加写FileOutputStream fos = new FileOutputStream(new File("b.txt"),true);for (int i = 0; i < 10; i++) {fos.write("哈哈哈".getBytes());//换行写fos.write("\r\n".getBytes());}fos.close();}

2.2 字节输入流InputStream

它是一个抽象类,是所有字节输入流类的超类
共性方法

  • int read()
  • int read(byte[] b)
  • void close

2.2.1 文件字节输入流FileInputStream

作用:把硬盘中的数据,读取到内存中使用

构造方法

  • FileInputStream(String name)
  • FileInputStream(File file)

构造方法的作用

  1. 创建一个FileInputStream对象
  2. 把FileInputStream对象指向指定构造方法中要读取的文件

读取数据原理(硬盘—>内存)
Java程序 —> JVM —>OS —>OS调用读取数据的方法 —> 读取文件

字节输出流的使用步骤

  1. 创建FileInputStream对象,构造方法中绑定要读取的数据源
  2. 调用FileInputStream对象的read方法,读取文件
  3. 释放资源

注意:read每调用一次指针都会后移一位,如果while循环括号中不保存读取的值,输出的就是跳位读取的值。

一次读取一个字节

 public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("a.txt");int len = 0;while((len = fis.read())!=-1){//读取一个字节并返回 文件末尾返回-1System.out.print((char) len);}fis.close();}

一次读取多个字节
int read(byte[] b):
注意:byte[]的作用是起缓冲作用,存储每次读取到的多个字节。数组长度一般定义为1024(1kb)或者1024的整数值。int返回值是每次读取的有效字节个数。

原理:创建一个byte数组,数组元素的初始值为0。开始读取,把读取出的数据存入byte数组,指针移动,b.length是一次读取的字节个数。new String()可以把byte数组转换为字符串输出。read方法的返回值是有效读取字节个数。


 public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("a.txt");byte[] bytes = new byte[1024];int len = 0;while((len = fis.read(bytes))!=-1){System.out.print(new String(bytes,0,len));//打印byte中存的有效位}}

2.3 字节流练习-文件复制

原理
创建一个输入流的对象,再创建一个输出流的对象,然后输入流对象读取文件内容,写入输出流指向的对象处。
注意:应该先关闭输出流(写),再关闭输入流(读)。因为写完了一定读完了,但读完了不一定写完了。应该先开启输入流,再开启输出流,先读后写。

 public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("D:\\1.png");FileOutputStream fos = new FileOutputStream("E:\\1.png");byte[] bytes = new byte[1024];int len = 0;while((len=fis.read(bytes))!=-1){fos.write(bytes,0,len);}fos.close();fis.close();}

2.4 字节流读文件存在的问题

在读取中文字符的时候,可能不会显示完整的字符,因为一个中文可能占用多个字节。按字节流读取,每次只能读取字符的一部分。所以文本文件一般用字符流进行读写
GBK:1个中文2个字节
UTF8:1个中文3个字节

3 字符流

3.1 字符输入流Reader

字符输入流类最顶层的父类,是一个抽象类。

共性方法

  • int read()
  • int read(char[] c)
  • void close()

3.1.1 文件字符输入流FileReader

作用:把硬盘文件中的数据以字符的方式读取到内存中

构造方法:创建一个FileReader对象,把FileReader对象指向要读取的文件/文件路径

  • FileReader(String name)
  • FileReader(File file)

使用步骤

  1. 创建FileReader对象,构造方法中绑定要读取的数据源
  2. FileReader对象调用read方法
  3. 关闭,释放资源

一次读取一个字符

 public static void main(String[] args) throws IOException {FileReader fd = new FileReader("a.txt");int len = 0;while((len = fd.read())!=-1){System.out.print((char) len);}fd.close();}

一次读取多个字符

字符数组 —> 字符串 new String(char[], int off, int len)构造方法

 public static void main(String[] args) throws IOException {FileReader fd = new FileReader("a.txt");char[] c = new char[1024];int len = 0;while((len = fd.read(c))!=-1){System.out.print(new String(c,0,len));}fd.close();}

3.2 字符输出流Writer

共性方法

  • void write(int c) 写入单个字符。
  • void write(char[] cbuf) 写入字符数组。
  • abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
  • void write(String str) 写入字符串。
  • void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
  • void flush() 刷新该流的缓冲。
  • void close() 关闭此流,但要先刷新它。

3.2.1 文件字符输出流FileWriter

作用:内存中的字符数据写入文件中

构造方法

  • FileWriter(String name)
  • FileWriter(File file)

作用:创建FileWriter对象,根据构造方法中传递的文件/文件路径创建文件,会把FileWriter对象指向创建好的文件中。

使用步骤

  1. 创建FileWriter对象,构造方法中绑定写入数据的目的地。
  2. 使用FileWriter中的方法write,把数据写入到内存缓冲区中。(字符转换为字节的过程)
  3. 使用FileWriter中的方法flush,把内存缓冲区的数据,刷新到文件中。
  4. 释放资源(会先把内存缓冲区的数据刷新到文件中)

写入单个字符

 public static void main(String[] args) throws IOException {FileWriter fw = new FileWriter("a.txt");//绑定写入位置fw.write(97);//写入缓冲区 字符-->字节fw.flush();//写入文件fw.close();//释放资源}

flush和close方法的区别
close在关闭之前会先把内存缓冲区的数据刷新到文件中,但close之后不能继续使用write方法。flush同样也是刷新操作,但flush之后可以继续使用write方法。

其他写入方法

  • void write(char[] c):写入字符数组
  • abstract void write(char[] c, int off, int len):写入字符数组的某一部分
  • void write(String str):写入字符串
  • void write(String str, int off, int len):写入字符串的某一部分
    public static void main(String[] args) throws IOException {FileWriter fw = new FileWriter("a.txt");char[] c = {'a','b','c','d','e','f'};fw.write(c);fw.write('\n');fw.write(c,3,3);String str = "嘻嘻哈哈呵呵";fw.write(str);fw.write('\n');fw.write(str,1,3);fw.close();}

续写和换行写
同字节流输出

 public static void main(String[] args) throws IOException {FileWriter fw = new FileWriter("c.txt",true);for (int i = 0; i < 10; i++) {fw.write("哈哈哈"+i);fw.write("\r\n");}fw.close();}

4 IO流的异常处理

在JDK1.7之前可以使用try-catch-finally处理流中的一次

 public static void main(String[] args) {FileWriter fw = null;try{fw = new FileWriter("F:\\c.txt",true);for (int i = 0; i < 10; i++) {fw.write("哈哈哈"+i);fw.write("\r\n");}}catch (IOException e){e.printStackTrace();}finally {if(fw != null){try {fw.close();} catch (IOException e) {e.printStackTrace();}}}}

JDK7的新特性:可以在try后增加一个()( )(),括号中可以定义流对象,那么这个流对象的作用域就在try中有效,try执行完后,流对象自动释放,不用写finally【常用】

    public static void main(String[] args) {try(FileWriter fw = new FileWriter("F:\\c.txt",true)){for (int i = 0; i < 10; i++) {fw.write("哈哈哈"+i);fw.write("\r\n");}}catch (IOException e){e.printStackTrace();}System.out.println("哈哈哈哈哈");}

JDK9的新特性,try前面可以定义对象,在try后边的()中可以引入流对象的名称。try执行完毕后,流对象可以释放掉,不需要写finally。【不常用】

 public static void main(String[] args) {FileReader fr = new FileReader("c.txt");FileWriter fw = new FileWriter("d.txt");try(fr;fw){char[] c = new char[1024];int len = 0;while((len = fr.read(c))!=-1){fw.write(c);}fw.flush();}catch (IOException e){e.printStackTrace();}System.out.println("哈哈哈哈哈");}

5 属性集

java.util.Properties 继承于Hashtable,来表示一个持久的属性集。是唯一一个和IO流相结合的集合。

它使用键值结构存储数据,每个及其对应都是一个字符串。该类也被许多Java类使用,比如获取系统属性时, System.getProperties 方法就是返回一个Properties 对象。

使用Properties存储数据并遍历取出

操作字符串的特有方法

  • Object setProperty(String key, String value):相当于map.put(k, v)
  • String getProperty(String key):相当于map.get(k)
  • Set <String> stringPropertyNames():相当于map.keySet()
 public static void main(String[] args) {Properties prop = new Properties();prop.setProperty("张三","20");prop.setProperty("李四","25");prop.setProperty("王五","30");Set<String> set = prop.stringPropertyNames();for(String key: set){String value = prop.getProperty(key);System.out.println(key+" "+value);}}
  • 可以使用store方法把集合中的临时数据,持久化写入硬盘中存储
  • void store(OutputStream out, String comments):字节输出流,不能写中文
  • void store(Writer writer, String comments):字符输出流,可以写中文

comments是注释,用来解释保存的文件是做什么的,不可以使用中文,默认是Unicode编码,一般使用空字符串

使用步骤

  1. 创建一个Proprorities对象,添加数据
  2. 创建字节输出流/字符输出流对象,构造方法绑定输出位置
  3. 使用store方法把集合中的临时数据持久化写入硬盘中。
  4. 释放输出流对象
 public static void main(String[] args) throws IOException {Properties prop = new Properties();prop.setProperty("张三","20");prop.setProperty("李四","25");prop.setProperty("王五","30");FileWriter fw = new FileWriter("e.txt");prop.store(fw, "");fw.close();}
  • 可以使用load方法,把硬盘中保存的文件,读取到集合中使用
  • void load(InputStream in):字节输入流,不能读取含有中文的键值对
  • void load(Reader r):字符输入流,可以读取含有中文的键值对

使用步骤

  1. 创建一个Properties对象,load堆区保存键值对的文件
  2. 遍历Properties集合

注意

  • 键值对文件中,键和值默认的连接符可以使用=、空格
  • 可以使用#来注释,被注释的键值对不会再读取
  • 键和值默认都是字符串,不用再加引号
 public static void main(String[] args) throws IOException {Properties prop = new Properties();prop.load(new FileReader("f.txt"));Set<String> set = prop.stringPropertyNames();for(String key: set){System.out.println(key+" "+prop.getProperty(key));}}

6 缓冲流

缓冲流,也叫高效流,是对4个基本的FileXxx 流的增强,所以也是4个流,按照数据类型分类:
字节缓冲流: BufferedInputStream , BufferedOutputStream
字符缓冲流: BufferedReader , BufferedWriter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。

6.1 字节缓冲流

6.1.1 字节缓冲输出流BfferedOutputStream

继承自OutputStream,可使用父类共性方法(见2.1)

构造方法

  • BufferedOutputStream(OutputStream out):创建一个新的缓冲输出流,以数据写入指定的底层输出流。
  • BufferedOutputStream(OutputSteam out, int size):创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。

使用步骤

  1. 创建FileOutputStream对象,构造方法中绑定输出位置。
  2. 创建BufferedOutputStream对象,构造方法中传递fos对象,提高fos对象效率。
  3. 使用bos对象的write方法,把数据写入到内部缓冲区中。
  4. 使用bos对象的flush方法,把缓冲区的数据刷新到文件中。
  5. 释放资源,close会先调用flush刷新数据再关闭(所以第四步可省略)
 public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("b.txt");BufferedOutputStream bos = new BufferedOutputStream(fos);bos.write("写入内部缓冲区".getBytes());//字节输出流 用字节bos.flush();bos.close();}

6.1.2 字节缓冲输入流BfferedInputStream

继承自InputStream,可使用父类共性方法(见2.2)

构造方法

  • BufferedInputStream(InputStream in):创建一个新的缓冲输入流,保存参数输入流in。
  • BufferedInputStream(InputSteam in, int size):创建一个具有指定缓冲区大小的BufferedInputStream保存其参数,即输入流。

使用步骤

  1. 创建FileInputStream对象,构造方法中绑定读取位置。
  2. 创建BufferedInputStream对象,构造方法中传递fis对象,提高fis对象的读取效率。
  3. 使用bis对象的read方法,把数据写入到内部缓冲区中。
  4. 释放资源。
    public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("a.txt");BufferedInputStream bis = new BufferedInputStream(fis);/*int len = 0;while((len = bis.read()) != -1){System.out.print((char)len);}bis.close();*/byte[] bytes = new byte[1024];int len = 0;while((len = bis.read(bytes))!=-1){System.out.println(new String(bytes));}}

6.1.3 基本和缓冲效率比较

 public static void main(String[] args) throws IOException {long s = System.currentTimeMillis();FileInputStream fis = new FileInputStream("D:\\1.png");FileOutputStream fos = new FileOutputStream("E:\\1.png");BufferedInputStream bis = new BufferedInputStream(fis);BufferedOutputStream bos = new BufferedOutputStream(fos);byte[] bytes = new byte[1024];int len = 0;while((len=bis.read(bytes))!=-1){bos.write(bytes,0,len);}bos.close();bis.close();long e = System.currentTimeMillis();System.out.println(e-s);}

文件复制4MB的ppt的效率比较:

基本流(一次读一个字节):17757 ms
缓冲流(一次读一个字节):121 ms
基本流 + 数组缓冲区(一次读多个字节):27 ms
缓冲流 + 数组缓冲区(一次读多个字节):9 ms

6.2 字符缓冲流

6.2.1 字符缓冲输出流BufferedWriter

继承自Writer,可使用父类共性方法(见3.2)

构造方法

  • BufferedWriter(Writer out):创建一个使用默认大小输出缓冲区的缓冲字符输出流。
  • BufferedWriter(Writer out, int size):创建一个使用指定大小输出缓冲区的缓冲字符输出流。

特有方法

  • void newLine():写入一个行分隔符,它会根据不同的操作系统,获取不同的行分隔符。

使用步骤

  1. 创建字符输出流对象,构造方法中传递写入地址
  2. 创建字符缓冲区输出流对象,构造方法中传递字符输出流
  3. 调用flush,将内存缓冲区中的数据刷新到文件中
  4. 释放资源
 public static void main(String[] args) throws IOException {BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));for (int i = 0; i < 10; i++) {bw.write("哈哈哈哈");bw.newLine();bw.write("嘻嘻嘻嘻");bw.newLine();}bw.close();}

6.2.2 字符缓冲输入流BufferedReader

继承自Reader,可使用父类共性方法(见3.1)

构造方法

  • BufferedReader(Reader in):创建一个使用默认大小输入缓冲区的缓冲字符输入流。
  • BufferedReader(Reader in, int size):创建一个使用指定大小输入缓冲区的缓冲字符输入流。

特有方法

  • String readLine():读取一行文本,读取一行数据,流末尾返回null,readLine不读换行符

使用步骤

  1. 创建字符输入流对象,构造方法中传递读取地址
  2. 创建字符缓冲区输入流对象,构造方法中传递字符输入流
  3. 调用read/readLine读取
  4. 释放资源
 public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new FileReader("b.txt"));String line = null;while((line = br.readLine())!=null){System.out.println(line);}}

6.3 缓冲流练习-文本排序

b.txt内容:
7.77777777777777
3.张三3333333333
5.王五5555555555
1.大一1111111111
4.李四4444444444
2.小二2222222222
6.六六6666666666

 public static void main(String[] args) throws IOException {Map<String , String> map = new HashMap<>();BufferedReader br = new BufferedReader(new FileReader("b.txt"));BufferedWriter bw = new BufferedWriter(new FileWriter("nb.txt"));String line;while((line = br.readLine())!=null){String[] split = line.split("\\.");map.put(split[0],split[1]);}//map会自动排序for(String key: map.keySet()){String value = map.get(key);bw.write(key+"."+value);bw.newLine();}bw.close();br.close();}

7 转换流

7.1 字符编码和字符集

字符编码
计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。按照某种规则,将字符存储到计算机中,称为编码 。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码 。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本f符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象。

字符编码Character Encoding : 就是一套自然语言的字符与二进制数之间的对应规则。

字符集
字符集 Charset :也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。计算机要准确的存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBK字符集、Unicode字符集等。

ASCII是最基本的编码表,GBK是中文编码表
Unicode是万国码,兼容各种语言,是应用中优先采用的编码。

7.2 编码常见问题

例如:在IDEA中,使用FileReader 读取项目中的文本文件。由于IDEA的设置,都是默认的UTF-8编码,所以没有任何问题。但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码。

解决方法:使用转换流

7.3 转换流相关内容

字节转换为字符(解码)
FileInputStream —> 查询编码表 —> FileReader

7.3.1 OutputStreamWriter

字符流通向字节流的桥梁
可以指定编码格式
写入你想写入的编码格式的文件中

构造方法

  • OutputStreamWriter(OutputStream out):创建使用默认字符编码的OutputStreamWriter(utf8)
  • OutputStreamWriter(OutputStream out, String charSet):创建使用指定字符编码的OutputStreamWriter

使用步骤

  1. 创建OutputStreamWriter对象,构造方法中传递字节输出流和指定编码集
  2. 使用osw对象中的write,把字符转换为字节存在缓冲区中
  3. 使用osw对象中的flush把字节刷新到文件中
  4. 释放资源

你好 GBK 4字节 UTF8 6字节

    public static void main(String[] args) throws IOException {OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"gbk");osw.write("你好");osw.close();}

7.3.2 InputStreamReader

字节流通向字符流的桥梁
可以指定编码格式
读取字节解码为字符 把看不懂的变成看得懂的

构造方法

  • InputStreamReader(InputStream in):创建使用默认字符编码的OutputStreamWriter(utf8)
  • InStreamReader(InputStream in, String charSet):创建使用指定字符编码的InputStreamReader

使用步骤

  1. 创建InputStreamReader对象,构造方法中传递字节输入流和指定编码集
  2. 使用isw对象中的read读取文
  3. 释放资源

注意:如果文件编码和指定编码不一致,则会发生乱码

    public static void main(String[] args) throws IOException {InputStreamReader isr = new InputStreamReader(new FileInputStream("utf8.txt"),"utf-8");int len = 0;while((len = isr.read())!=-1){System.out.print((char)len);}isr.close();}

7.4 练习:转换文件编码

将GBK编码的文本文件,转换为UTF8编码的文本文件

public static void main(String[] args) throws IOException {InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.txt"),"gbk");OutputStreamWriter osr = new OutputStreamWriter(new FileOutputStream("gbk2utf8.txt"),"utf-8");int len = 0;while((len = isr.read()) != -1){osr.write(len);}osr.close();isr.close();}

8 序列化和反序列化

8.1 概念

ObjectOutputStream对象的序列化流
把对象以流的方式写入到文件中保存,叫写对象,也叫对象的序列化。对象中包含的不仅是字符,使用字节流。

ObjectInputStream对象的反序列化流
把文件中的对象,以流的方式读取出来,叫读对象,也叫对象的反序列化。文件保存的都是字节,使用字节流。

8.2 对象的序列化流ObjectOutputStream

构造方法

  • ObjectOutputStream(OutputStream out)

特有方法

  • void writeObject(Object obj)

使用步骤

  1. 创建ObjectOutputStream对象,构造方法中传递字节输出流
  2. 使用writeObject方法写入对象
  3. 释放资源

序列化和反序列化时,会抛出NotSerializableException没有序列化异常。
类通过实现Serializable接口以启动序列化功能,没有实现此接口的类无法使其任何状态序列化或反序列化。
Serializable接口也叫标记型接口,进行序列化和反序列化,必须要实现Serializable接口,给类添加标记。在使用时,会检测是否有标记。

使用前提
Person类的实现 要加上implement Serializable

 public static void main(String[] args) throws IOException {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));oos.writeObject(new Person("张三",15));oos.close();}

8.3 对象的反序列化流ObjectInputStream

构造方法

  • ObjectInputStream(InputStream in)

特有方法

  • void readObject(Object obj) 读取对象

使用步骤

  1. 创建ObjectOutputStream对象,构造方法中传递字节输入流
  2. 使用writeObject方法读取对象
  3. 释放资源
  4. 打印对象

readObject方法声明抛出了ClassFoundException,class文件找不到异常,当不存在对象的class文件时抛出异常
使用前提
Person类的实现 要加上implement Serializable
对象的class类文件要存在

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Person.txt"));
Object o = ois.readObject();
ois.close();
System.out.println(o);

【注意!!!】
InvalidClassException异常:序列化之后对类进行更改之后,不重新序列化,而是直接反序列化会出现异常。

因为javac编译器会把java文件编译生成class文件。类如果实现了Serializable接口,就会根据类的定义给类的class文件添加一个序列化号serialVersionUID,输出的文件也会写入这个ID,反序列化的时候,会使用class文件的序列号和输出文件的序列号比较,如果ID一致,则反序列化一致,否则会抛出InvalidClassException异常

而修改了类的定义之后,会给class文件重新编译生成一个新的序列号,但是输出文件的序列号没有改。

解决方案:手动给类加一个序列号。无论是否修改类都不再修改序列号。

自定义类中添加成员常量。

private static final long serialVersionID = 1L;

瞬态关键字transient
static静态关键字:静态优先于非静态加载到内存中,(静态优先于对象),所以static修饰的成员变量是不能被序列化的,序列化的都是对象。
【在上例中,如果Person类的age成员变量是静态的,序列化和非序列化age将永远是初始值0,无法更改】

transient瞬态关键字:被它修饰的成员变量不能被序列化。如果想要对象中的成员变量不被序列化,可以使用瞬态关键字。

8.4 练习:序列化集合

当我们想在文件中保存多个对象的时候,可以把对象存在集合中,对集合进行序列化和反序列化。

 public static void main(String[] args) throws IOException, ClassNotFoundException {ArrayList<Person> list = new ArrayList<>();list.add(new Person("张三",15));list.add(new Person("李四",19));list.add(new Person("王五",20));ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("PersonList.txt"));oos.writeObject(list);ObjectInputStream ois = new ObjectInputStream(new FileInputStream("PersonList.txt"));Object o = ois.readObject();ArrayList<Person> list2 = (ArrayList<Person>) o;for (Person p : list2){System.out.println(p);}ois.close();oos.close();}

9 打印流

9.1 PrintSteam类

平时我们在控制台打印输出,是调用print方法和println方法完成的,这两个方法都来自于java.io.PrintStream类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式。

特点

  • 不会抛出IO异常
  • 只负责输出,不负责读取
  • 特有方法print、println

构造方法

  • PrintStream(File file):输出目的地是一个文件
  • PrintStream(OutputStream out):输出目的地是一个字节输出流
  • PrintStream(String path):输出目的地是一个文件路径

注意

  • 如果用继承父类的write方法写数据,查看数据的时候就会查询编码表,再打印
  • 如果使用特有方法print和println则会原样输出
 public static void main(String[] args) throws IOException, ClassNotFoundException {PrintStream ps = new PrintStream("a.txt");ps.write(97);ps.write('\n');ps.println(97);ps.print("a1#$@哈哈哈");ps.close();}

可以改变输出语句的目的地,即打印流的流向。
输出语句,默认在控制台输出,使用System.setOut方向改变输出语句的目的地改为参数中传递的打印流的目的地。

 public static void main(String[] args) throws IOException, ClassNotFoundException {System.out.println("控制台输出:哈哈哈");PrintStream ps = new PrintStream("打印流输出");System.setOut(ps);System.out.println("打印流输出:哈哈哈");//控制台不输出这一句 而是写在"打印流输出"文件中}

【Java】关于Java中的各种流相关推荐

  1. java 从键盘中读取字符流 自定义异常

    public class Demo{public static void main(String[] args) {Demo d = new Demo();d.in();}public void in ...

  2. 跟我学 Java 8 新特性之 Stream 流基础体验

    转载自   跟我学 Java 8 新特性之 Stream 流基础体验 Java8新增的功能中,要数lambda表达式和流API最为重要了.这篇文章主要介绍流API的基础,也是流API系列的第一篇文章, ...

  3. java 流的概念_举例讲解Java中的Stream流概念

    1.基本的输入流和输出流 流是 Java 中最重要的基本概念之一.文件读写.网络收发.进程通信,几乎所有需要输入输出的地方,都要用到流. 流是做什么用的呢?就是做输入输出用的.为什么输入输出要用&qu ...

  4. java中的各种流(老师的有道云笔记)

    内存操作流-字节 之前的文件操作流是以文件的输入输出为主的,当输出的位置变成了内存,那么就称为内存操作流.此时得使用内存流完成内存的输入和输出操作. 如果程序运行过程中要产生一些临时文件,可采用虚拟文 ...

  5. 关于java中的各种流

    个人的最大感觉,你如果是想灵活使用流,那就去看jdk文档吧,上面说的很清楚,不需要去死记的,反正我是一次性记不住这么多东西. Input和Output 1. stream代表的是任何有能力产出数据的数 ...

  6. java输出流输入流的使用_Java中的IO流之文件输入输出流

    Java中的IO流之文件输入输出流 1.文件流介绍 文件流是以字节为单位进行读写文件的,所以属于字节流,并且是低级流.文件流位于java.io包下. 输入输出流分别是FileInputSteam和Fi ...

  7. 详细讲解JAVA中的IO流

    一.流的概念        流(stream)的概念源于UNIX中管道(pipe)的概念.在UNIX中,管道是一条不间断的字节流,用来实现程序或进程间的通信,或读写外围设备.外部文件等.        ...

  8. 四十三、深入Java中的数组流,数据流和对象流操作

    @Author:Runsen @Date:2020/6/8 作者介绍:Runsen目前大三下学期,专业化学工程与工艺,大学沉迷日语,Python, Java和一系列数据分析软件.导致翘课严重,专业排名 ...

  9. io流图解 java_详细讲解JAVA中的IO流

    一.流的概念 流(stream)的概念源于UNIX中管道(pipe)的概念.在UNIX中,管道是一条不间断的字节流,用来实现程序或进程间的通信,或读写外围设备.外部文件等. 一个流,必有源端和目的端, ...

  10. java替换数组中的元素_如何使用Java 8流快速替换列表中的元素

    java替换数组中的元素 假设您有一个项目清单: List<String> books = Arrays.asList("The Holy Cow: The Bovine Tes ...

最新文章

  1. dedecms 标签使用集锦
  2. python机器学习梯度下降求解逻辑回归
  3. 【转载】 Single sign on
  4. simple log test
  5. thinkphp5引入调用外部类
  6. 越界操作导致程序崩溃的原理
  7. 【渝粤题库】广东开放大学 大学生创业基础 形成性考核
  8. 罗永浩如果倒过来过,也很励志
  9. 总线收发器是干什么的_总线耦合器到底是做什么用的
  10. 夕四今晚加班到2点30,而王二还不打算走《打工人的那些事》
  11. 瑞幸自曝虚假交易22亿,App却反冲 TOP 1
  12. 有关“A New Adversarial Embedding Method for Enhancing Image Steganography“的理解
  13. 由浅入深的分析HashMap原理
  14. 怎么把图片缩小尺寸,缩小图片尺寸方法
  15. html 银联图标,银联标志logo图片 云闪付app扫银联标识领获红包
  16. C#动态创建lambda表达式
  17. 对AutoResetEvent和ManualResetEvent的理解
  18. 杂项:MIME(多用途互联网邮件扩展类型)百科
  19. it is forbidden to set both [discovery.seed_hosts] and [discovery.zen.ping.unicast.hosts]
  20. 罗克韦尔AB PLC RSLogix模拟量IO模块基本介绍

热门文章

  1. 度量时间差和jiffies计数器
  2. TRACE (VC)
  3. android power 按键,Android Framework层Power键关机流程(一,Power长按键操作处理)
  4. bootstrap3 表单构建器_FastReport.NET报表设计器连接到OracleDB关系数据库
  5. 检测范围_论文检测系统的检测范围有哪些
  6. python导出数据顿号做分隔符_Python语言和matplotlib库做数据可视化分析
  7. Node 中的path模块
  8. LeetCode 536. 从字符串生成二叉树(递归)
  9. LeetCode 156. 上下翻转二叉树(DFS)*
  10. LeetCode 1417. 重新格式化字符串