【Java】关于Java中的各种流

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("打印流输出:哈哈哈");//控制台不输出这一句 而是写在"打印流输出"文件中}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/480960.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

支付系统-系统架构

本文主要是从支付架构、支付流程分析、支付核心逻辑、支付基础服务、支付安全五个方面来详细讲述支付系统架构 &#xff08;1&#xff09;、架构的定义&#xff1a;架构一定是基于业务功能来展开的&#xff0c;主要是制定技术规范、框架&#xff0c;指导系统落地&#xff1b;好…

领域应用 | 智能导购?你只看到了阿里知识图谱冰山一角

在刚刚结束的2017第四届世界互联网大会上&#xff0c;评选出了年度18项代表性的领先科技成果&#xff0c;阿里云ET大脑就是其中之一。众所周知&#xff0c;融合了先进的大数据、人工智能技术的阿里云ET大脑已经在智慧城市、智慧交通等众多领域得到了应用和推广。但你知不知道&a…

美团技术团队-大众点评搜索基于知识图谱的深度学习排序实践

美团技术团队博客网址&#xff1a;https://tech.meituan.com/2019/02/28/root-clause-analysis.html 1. 引言挑战与思路搜索是大众点评App上用户进行信息查找的最大入口&#xff0c;是连接用户和信息的重要纽带。而用户搜索的方式和场景非常多样&#xff0c;并且由于对接业务种…

NLP、炼丹技巧和基础理论文章索引

玩家你好 恭喜你捡到了一个来自上古时期的*七*星*炼*丹*炉*&#xff0c;只见炉壁上镶嵌着自然语言处理、推荐系统、信息检索、深度炼丹、机器学习、数学与基础算法等失传已久的江湖秘术。熔炉中虽然已有一层厚厚尘土&#xff0c;却依然掩盖不住尘埃下那一颗颗躁动不安的仙丹。 …

支付系统-概念与架构

一、什么是支付系统 自古以来&#xff0c;所有的商业活动都会产生货币的收款与付款行为。在人类漫长的历史长河中&#xff0c;记录收付款行为的方式不断迭代&#xff1a;古代的账房先生通过手工记账&#xff0c;工业社会通过收银机机械记账…… 今天&#xff0c;进入了互…

论文浅尝 | Reinforcement Learning for Relation Classification

论文链接&#xff1a;http://aihuang.org/p/papers/AAAI2018Denoising.pdf来源&#xff1a;AAAI 2018MotivationDistant Supervision 是一种常用的生成关系分类训练样本的方法&#xff0c;它通过将知识库与非结构化文本对齐来自动构建大量训练样本&#xff0c;减少模型对人工标…

各大集团技术团队社区-微软-阿里-腾讯-百度-美团

百度AI社区&#xff1a;http://ai.baidu.com/forum/topic/list/169 阿里云栖社区&#xff1a;https://yq.aliyun.com/articles/ 美团技术团队&#xff1a;https://tech.meituan.com/2019/02/28/root-clause-analysis.html 微软行业博客&#xff1a;https://cloudblogs.microsof…

2019年终总结与新年重磅福利

一只小狐狸带你解锁NLP/ML/DL秘籍圣诞已过&#xff0c;元旦即临回首2019&#xff0c;我们收获满满展望2020&#xff0c;我们砥砺前行在这新春佳节之际小夕给大家送上七福大礼包别怕太沉&#xff0c;赶紧收下吧~~~自然语言处理花生仁????神经网络与炼丹鲜虾丸????机器学…

支付系统-会计核心

一、复式记账 第一个问题&#xff1a;如何理解账务系统单边记账&#xff0c;会计系统复式记账&#xff1f; 有些公司内部账户之间转账都采用复式记账法&#xff0c;如充值、提现交易&#xff0c;他们在账务系统都记单边流水&#xff0c;等和银行对账后&#xff0c;在会计系统复…

【Java】函数式编程

1 函数式接口 1.1 概念 函数式接口是有且仅有一个抽象方法的接口&#xff0c;可以包括静态和默认方法。 FunctionalInterface&#xff1a;加上注解&#xff0c;检测是否的函数式接口 FunctionalInterface public interface MyFunctionInterface {public abstract void meth…

领域应用 | 中医临床知识图谱的构建与应用

本文转载自公众号&#xff1a;e医疗。 知识图谱是近年来知识管理和知识服务领域中出现的一项新兴技术&#xff0c;它为中医临床知识的关联、整合与分析提供了理想的技术手段。我们基于中医医案等临床知识源&#xff0c;初步建立了由疾病、证候、症状、方剂、中药等核心概念所构…

还在随缘炼丹?一文带你详尽了解机器学习模型可解释性的奥秘

一只小狐狸带你解锁NLP/ML/DL秘籍正文来源&#xff1a;腾讯技术工程所谓炼丹&#xff0c;就是将大量灵材使用丹炉将其凝炼成丹。练成的灵丹蕴含灵材的大部分特性&#xff0c;方便携带&#xff0c;容易吸收。高级仙丹在炼制中更是能吸收天地灵气从而引发天地异象。深度学习的模型…

支付系统-财务系统

一、概述 从业多年经手过的印象比较深刻的几个系统&#xff0c;我将其中对账及清结算系统进行了剥离&#xff0c;着重为大家分享一下支付系统需要具备哪些功能&#xff0c;以及当时在实际搭建过程中&#xff0c;我们对于功能及整体做出的具体选择。 首先如图所示&#xff0c;支…

论文浅尝 | CFO: Conditional Focused Neural Question Answering

Zihang Dai, Lei Li, and Wei Xu. 2016. CFO: Conditional focused neural question answering with large-scale knowledge bases. In Proceedings of ACL, pages 800–810.链接&#xff1a;http://aclweb.org/anthology/P/P16/P16-1076.pdfGitHub 项目地址&#xff1a;https:…

【Java】Stream流和方法引用

1 Stream流 1.1 Stream流优化过滤集合 传统方式 用一个循环过滤姓张的人用一个循环过滤名字长度大于2的人 public static void main(String[] args) {ArrayList<String> list new ArrayList<>();list.add("张三");list.add("李四");list.a…

Python中输入和输出

版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 https://blog.csdn.net/xiaokang123456kao/article/details/73009480 </div><link rel"stylesheet" href"https://csdnimg.cn/release/phoenix/template/css/ck_htm…

刘志明 | 知识图谱及金融相关

本文转载自公众号&#xff1a;挖地兔&#xff0c;本文的作者刘志明先生也是 Tushare 的作者。 Tushare 是一个基于 Python 语言的免费、开源的财经数据接口包&#xff0c;可以为金融量化分析人员提供快速、整洁和多样的结构化数据&#xff0c;帮助量化投资人员节省数据采集和清…

模型训练太慢?显存不够用?这个算法让你的GPU老树开新花

一只小狐狸带你解锁NLP/ML/DL秘籍作者&#xff1a;小鹿鹿鹿&#xff0c;夕小瑶老板&#xff0c;咱们就一台Titan Xp&#xff0c;训不动BERT呀没钱买机器&#xff0c;自己想办法。委屈T^T我听说混合精度训练可以从算法上缓解这个问题&#xff1f;喵喵喵&#xff1f;&#xff1f;…

【Java】Junit、反射和注解的笔记

1 Junit 黑盒测试&#xff1a;不需要写代码&#xff0c;给输入值&#xff0c;看程序输出是否符合期望 白盒测试&#xff1a;需要写代码&#xff0c;关注程序具体的执行流程 Junit —> 白盒测试 步骤 定义一个测试类&#xff08;测试用例&#xff09; 【命名&#xff1a;类…