什么是"IO流"?
从字面意思理解,"I" input 输入,"O" output 输出,“流”又怎么去理解呢?数据的传输,可以看作是数据的一种流向,以内存为基准。即在Java中 流向内存的是输入流
,流出内存的则称为输出流。
Java中I/O操作指使用 java.io
包下的内容,进行输入,输出操作。输入数据也叫写入数据,输出数据也叫写出数据。
1. IO流分类
根据数据的流向分为:输入流和输出流
输入流: 把数据从设备之中读取到内存之中。
输出流: 把数据从内粗之中写出到设备之中。
根据数据的类型分为:字符流和字节流
字符流: 以字符为单位,进行读写的流。
字节流: 以字节为单位,进行读取的流。
输入输出流分类的超类(超类也就是父类的意思
)
输入流 | 输出流 | |
---|---|---|
字符流 | 字符流输入Reader | 字符流写出Writer |
字节流 | 字节流输入InputStream | 字节流写出OutputStream |
Jdk 1.8 手册之中可以看到字符流和字节流的子类
Writer 省略……
OutputStream 省略……
<center>
</center>
2. 文件的世界一切皆字节
计算机世界之中所有东西都将以二进制的形式进行保存,都是一个字节一个字节,传输时也亦然如此,所以字节流可以传输任意的文件数据,在操作流的时候,无论我们使用什么流对象,底层最终传输的还是我们的二进制。
一个字符=2个字节
一个字节=8个二进制
3. OutputStream(字节输出流)
java.io.OutputStream
抽象类是表示字节输出流 的所有类的超类 (父类),将指定字节信息输出到直接得位置。它定义了自己输出流的基本公共性功能(继承)。
子继父基本的公共性特征
id | 方法名 | 简述 |
---|---|---|
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开始输出到此输出流。也就是说从off个字节数开始读取一直到len个字节结束 |
4 | public abstract void write(int b) | 将指定的字节输出流。 |
以上五个方法则是字节输出流都具有的方法,由父类OutputStream定义提供,子类都会共享以上方法
3.1 FileOutputStream(字节输出流)
到这里我们可以直接想到的是,FileOutputStream
是 OutputStream
子类。是直接用于将数据写出到文件之中的。
FileOutputStream构造方法
FileOutputStream(File file) | 创建文件输出流以写入由指定的 File 对象表示的文件。 |
---|---|
FileOutputStream(File file, boolean append) | 创建文件输出流以写入由指定的 File 对象表示的文件。 |
FileOutputStream(String name) | 创建文件输出流以指定的名称写入文件。 |
FileOutputStream(String name, boolean append) | 创建文件输出流以指定的名称写入文件。 |
FileOutputStream(String name)
该方式多数常用
代码演示:
/**
* FileOutputStream(File file)
* FileOutputStream(File file, boolean append)
*/
File file = new File("C\\a.txt");
FileOutputStream fileOutputStream = new FileOutputStream(file);
//不清空文件,内容追加
FileOutputStream fileOutputStream1 = new FileOutputStream(file,true);
/**
* FileOutputStream(String name)
* FileOutputStream(String name, boolean append)
*/
FileOutputStream fileOutputStream2 = new FileOutputStream("C:\\a.txt");
//不清空文件,内容追加
FileOutputStream fileOutputStream3 = new FileOutputStream("C:\\a.txt",true);
当创建一个流对象时,需要直接或者间接的传入一个文件路径。如果实例化对象之后如果没有这个文件,则会自动创建这一个文件,如果有这个文件则会将这个文件进行清空。
TIPS: 创建输出流对象的时候,系统会自动去对应位置创建对应文件,而创建输出流对象的时候,文件不存在则会报FileNotFoundException异常,也就是系统找不到指定的文件异常。
可以看出,创建字节输出流对象大致做了三件事:
1.调用系统去创建文件
2.创建FileoutputStream对象
3.将数据写出到文件。
FileOutputStream 写出字节流
使用FileOutputStream写出数据主要通过 Writer
方法进行文件的写出。
Type | 方法 | 简述 |
---|---|---|
void | write(char[] cbuf, int off, int len) | 写入字符数组的一部分。 |
void | write(int c) | 写一个字符 |
void | write(String str, int off, int len) | 写一个字符串的一部分。 |
1.写入字符数组的一部分
//创建流对象
FileOutputStream fileOutputStream = new FileOutputStream("C:\\a.txt");
//创建字符数据
byte[] bytes = "I'm Juran".getBytes();
//写出数据到文件中
fileOutputStream.write(bytes);
//刷新缓存,强制写入
fileOutputStream.flush();
//关闭流对象。
fileOutputStream.close();
//写出结果
I'm Juran
write(char[] cbuf, int off, int len)
同时使用该方法也可以将整个字符数组直接写出到文件之中,off及len,可以理解为从字符数组中的off开始写出到len的位置2.写一个字符
//创建流对象
FileOutputStream fileOutputStream = new FileOutputStream("C:\\a.txt");
//写出单个字符文件中
fileOutputStream.write(97);
//刷新缓存,强制写入
fileOutputStream.flush();
//关闭流对象,不允许进行写出
fileOutputStream.close();
//文件最终显示内容为:a
write(int c)
将数字97 写入文件,在文件打开的时候会通过这个字符对应的ascll码,找到对应的字母。3. 写一个字符串的一部分。
//创建流对象
FileOutputStream fileOutputStream = new FileOutputStream("C:\\a.txt");
// 字符串转换为字节数组
byte[] b = "代码喜欢我,我喜欢代码".getBytes();
// 写出字节数组数据
fileOutputStream.write(b);
// 关闭资源
fileOutputStream.close();
//文件内容:代码喜欢我,我喜欢代码
4.FileOutputStream实现数据的追加续写、换行
每次创建和使用FileOutputStream对象之后我们原文件的内容都会被清空然后再将新数据重新写出到文件之中。为了让我们原有的内容不会被清空,构造方法中提供了两个构造方法,用于追加数据的写出。
FileOutputStream(File file, boolean append)
FileOutputStream(String name, boolean append)
构造方法中有一个boolean 类型的 参数,append
当该参数的为true时为追加内容,当该参数为false 时,表示将文件内容清空重新写出到该文件。
代码演示
//创建流对象
FileOutputStream fileOutputStream = new FileOutputStream("C:\\a.txt",true);
//创建字节数组
byte[] bytes = {97,98,99,100,101};
//使用循环将字节单个写出到文件
for (byte aByte : bytes) {
fileOutputStream.write(aByte);
fileOutputStream.write("\n".getBytes());
}
//关闭流对象。
fileOutputStream.close();
//最终输出结果
a
b
c
d
e
字符串这里我就不进行演示了。同理!!!
这里还有一个点关于不同系统之间字符可能会有一定的不同。
Windows系统里,每行结尾是
回车+换行
,即 \r\n
;Unix系统里,每行结尾只有
换行
,即 \n
;Mac系统里,每行结尾是
回车
,即 \r
。从 Mac OS X开始与Linux统一。4. InputStream(字节写入流)
java.io.InputStream
抽象类是表示字节输入流 的所有类的超类 (父类),读取字节信息到内存之中,它定义了自己输入流的基本公共性功能(继承)。
字节输入流的基本共性功能方法 :
id | 方法名 | 简述 |
---|---|---|
1 | public void close() | 关闭此输入流并释放与此流相关联的任何系统资源。 |
2 | public abstract int read() | 从输入流读取数据的下一个字节。 |
3 | public int read(byte[] b) | 该方法返回的int值代表的是读取了多少个字节,读到几个返回几个,读取不到返回-1 |
以上方法则是字节输输入流都具有的方法,由父类InputStream定义提供,子类都会共享以上方法
4.1 FileInputStream(字节写入流)
FileInputStream
是 OutputStream
子类。从文件中读取字节,将字节信息读入内存之中。
FileOutputStream构造方法
方法名 | 简述 |
---|---|
FileInputStream(File file) | 通过打开与实际文件的连接创建一个 FileInputStream 该文件由文件系统中的 File 对象 file 命名。 |
FileInputStream(String name) | 通过打开与实际文件的连接创建一个 FileInputStream 该文件由文件系统中路径名 name 名 |
构造方法代码演示
/**
* FileInputStream(File file)
* file对象创建流对象
*/
File file = new File("C:\\a.txt");
FileInputStream fileInputStream1 = new FileInputStream(file);
/**
* FileInputStream(String name)
* 使用文件名建立流对象。
*/
FileInputStream fileInputStream = new FileInputStream("C:\\a.txt");
- 使用写入流对象时,必须传入文件路劲,否则会抛出
FileNotFoundException
异常,直译”文件找不到异常“。
代码演示:FileInputStream读取字节数据(循环遍历读取入字节内容)
读取字节 :read
方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回 -1
,
//创建字节写入流对象
FileInputStream fileInputStream = new FileInputStream("C:\\a.txt"); //内容为abcde
//定义变量,作为有效个数
int len = 0;
//while循环 使用read 方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1
while ((len = fileInputStream.read()) != -1){
System.out.println((char) len);
}
//关闭资源
fileInputStream.close();
a
b
c
d
e
//控制台打印效果
代码演示:FileInputStream读取字节数据(将字节存入数据使用String对象)
使用字节数组读取 :read(byte[] b)
,每次读取b的长度个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回 -1
。
//创建字节写入流对象
FileInputStream fileInputStream = new FileInputStream("C:\\a.txt"); //内容为abcde
//接收变量
int len = 0;
//定义字节数组,作为装字节数据的容器
byte[] bytes = new byte[2];
//while循环 使用read 方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1
while ((len = fileInputStream.read(bytes)) != -1){
System.out.println(new String(bytes));
}
//关闭资源
fileInputStream.close();
//读取内容为
ab
cd
ed
刚才执行代码中最后产生了一个结果,我们明明只有五个字节但是我们却输出了六个自己,abcde
为什么会多了一个 d
? 这是由于数组中上次读取的数据并没有被替换,所以在我们读取最后一个字节的时候,e还是会存在数组里边。所以我们需要通过定义的 len
有效个数来决定最后取的数据到什么位置。
<center>
</center>
所以做出以下改进
//创建字节写入流对象
FileInputStream fileInputStream = new FileInputStream("C:\\a.txt"); //内容为abcde
//接收变量
int len = 0;
//定义字节数组,作为装字节数据的容器
byte[] bytes = new byte[2];
//while循环 使用read 方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1
while ((len = fileInputStream.read(bytes)) != -1){
System.out.println(new String(bytes,0,len)); //off ,len 开始取的字节位置,len 最后取的字节位置
}
//关闭资源
fileInputStream.close();
5、Reader(字符输入流)
java.io.Reader
抽象类是字符输入流 的所有类的超类 (父类),可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。
字符输入共性常用方法:
方法 | 简述 |
---|---|
abstract void close() | 关闭流并释放与之相关联的任何系统资源。 |
int read() | 读一个字符 |
int read(char[] cbuf) | 将字符读入数组。 |
abstract int read(char[] cbuf, int off, int len) | 将字符读入数组的一部分。 |
5.1 FileReader类
java.io.FileReader
类* 阅读字符文件的便利课。 该类的构造函数假定默认字符编码和默认字节缓冲区大小是适当的。
构造方法
方法 | 简述 |
---|---|
FileReader(File file) | 创建一个新的 FileReader ,给出 File读取。 |
FileReader(String fileName) | 创建一个新的 FileReader ,给定要读取的文件的名称。 |
构造方式,使用
//使用File对象,创建输入流对象
File file = new File("C:\\a.txt");
FileReader fileReader = new FileReader(file);
//使用文件名创建输入流对象
FileReader fileReader1 = new FileReader("C:\\a.txt");
FileReader 读取字符read()
每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1。
// 使用文件名称创建流对象
FileReader fr = new FileReader("C:\\a.txt");
// 定义变量,保存数据
int len ;
// 循环读取
while ((len = fr.read())!=-1) {
System.out.println((char)len);
}
// 关闭资源
fr.close();
6、Writer(字符输出流)
java.io.Reader
抽象类是字符输入流 的所有类的超类 (父类),可以将字符输出到文件中。它定义了字符输出流的基本共性功能方法。
字符输出流的基本共性功能方法
方法 | 简述 |
---|---|
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() | 关闭此流,但要先刷新它。 |
6.1 FileWriter类
Java.io.FileWriter
方便课写字符文件。 该类的构造函数假定默认字符编码和默认字节缓冲区大小是可以接受的。
构造方法
方法 | 简述 |
---|---|
FileWriter(File file) | 给一个File对象构造一个FileWriter对象。 |
FileWriter(File file, boolean append) | 给一个File对象构造一个FileWriter对象。给出一个带有布尔值的文件名,表示是否附加写入的数据。 |
FileWriter(String fileName) | 构造一个给定文件名的FileWriter对象。 |
FileWriter(String fileName, boolean append) | 构造一个FileWriter对象,给出一个带有布尔值的文件名,表示是否附加写入的数据。 |
构造方法,代码
// 第一种:使用File对象创建流对象
File file = new File("C:\\a.txt");
FileWriter fw = new FileWriter(file);
// 第二种:使用文件名称创建流对象
FileWriter fw = new FileWriter("C:\\a.txt");
写出字符 :write(int b)
方法,每次可以写出一个字符数据。
//使用文件名创建FileWriter对象
FileWriter fw = new FileWriter("C:\\a.txt");
//写出字符
fw.write(97);
//关闭资源
fw.close();
输出结果
a
数据写入后,请关闭流对象,如果不关闭,数据只是保存到缓冲区,并未保存到文件。
写出字符数组 :write(char[] cbuf)
方法,将char数据中的内容,写出到文件中。
//使用文件名创建FileWriter对象
FileWriter fw = new FileWriter("C:\\a.txt");
//写出字符
char[] chars = {97,98,99,100,101};
fw.write(chars);
//关闭资源
fw.close();
输出结果为:abcde
FileWriter的续写和换行
与InputStream中的用法一致
//使用文件名创建FileWriter对象
FileWriter fw = new FileWriter("C:\\a.txt",true);
//写出字符
fw.write("chars");
fw.write("\n");
fw.write("Juran");
fw.write("\n");
fw.write("hh");
//关闭资源
fw.close();
输出内容
chars
Juran
hh
字符流,只能操作文本文件,不能操作图片,视频等非文本文件。当我们单纯读或者写文本文件时 使用字符流 其他情况使用字节流
7、缓冲流
缓冲流也被称为高效流,为了提高字节读写和字符读写效率,减少了请求IO的次数。
缓冲流基本原理
1、使用了底层流对象从具体设备上获取数据,并将数据存储到缓冲区的数组内。
2、通过缓冲区的read()方法从缓冲区获取具体的字符数据,这样就提高了效率。
3、如果用read方法读取字符数据,并存储到另一个容器中,直到读取到了换行符时,将另一个容器临时存储的数据转成字符串返回,就形成了readLine()功能。
OutputStream 和 OutputWriter 都是通过read() 一个自己一个字节进行读取,此时用到缓冲流,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数的请求,从而提高读写的效率。
缓冲流分类
- 字节缓冲流:BufferedInputStream,BufferendOutputStream。
- 字符缓冲流:BufferedWriter,BufferedReader.
7.1 字节缓冲流。
构造方法
方法 | 简述 |
---|---|
BufferedInputStream(InputStream in) | 创建一个 BufferedInputStream并保存其参数,输入流 in ,供以后使用。 |
BufferedInputStream(InputStream in, int size) | 创建 BufferedInputStream具有指定缓冲区大小,并保存其参数,输入流 in ,供以后使用。 |
public BufferedOutputStream(OutputStream out) | 创建一个新的缓冲输出流,注意参数类型为OutputStream。 |
构造方法举例。
//通过输入流对象,创建字节缓冲流对象。(开发中常用)
FileInputStream fileInputStream = new FileInputStream("C:\\a.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
//通过输入流对象,创建字节缓冲流对象。
BufferedInputStream bufferedInputStream1 = new BufferedInputStream(new FileInputStream("C:\\a.txt"));
//通过输出流对象,创建字节缓冲流对象。
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("C:\\a.txt"));
这里我就不做具体测试了,总的来说合理使用缓冲流文件传输复制效果,翻倍。
这里给出几个例子都是我在参考文档中看过的,这里记录一下
使用缓冲流进行文件的高效复制(后续测试……)
缓冲流读写方法与基本的流是一致的,我们通过复制370多MB的大文件,测试它的效率。
- 基本流,代码如下:
public class BufferedDemo {
public static void main(String[] args) throws FileNotFoundException {
// 记录开始时间
long start = System.currentTimeMillis();
// 创建流对象
try (
FileInputStream fis = new FileInputStream("py.exe");//exe文件够大
FileOutputStream fos = new FileOutputStream("copyPy.exe")
){
// 读写数据
int b;
while ((b = fis.read()) != -1) {
fos.write(b);
}
} catch (IOException e) {
e.printStackTrace();
}
// 记录结束时间
long end = System.currentTimeMillis();
System.out.println("普通流复制时间:"+(end - start)+" 毫秒");
}
}
不好意思十分钟过去了还在玩命复制中...
- 缓冲流,代码如下:
public class BufferedDemo {
public static void main(String[] args) throws FileNotFoundException {
// 记录开始时间
long start = System.currentTimeMillis();
// 创建流对象
try (
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("py.exe"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copyPy.exe"));
){
// 读写数据
int b;
while ((b = bis.read()) != -1) {
bos.write(b);
}
} catch (IOException e) {
e.printStackTrace();
}
// 记录结束时间
long end = System.currentTimeMillis();
System.out.println("缓冲流复制时间:"+(end - start)+" 毫秒");
}
}
缓冲流复制时间:8016 毫秒
有的童鞋就要说了,我要更快的速度!最近看速度与激情7有点上头,能不能再快些?答案是当然可以
想要更快可以使用数组的方式,代码如下:
public class BufferedDemo {
public static void main(String[] args) throws FileNotFoundException {
// 记录开始时间
long start = System.currentTimeMillis();
// 创建流对象
try (
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("py.exe"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copyPy.exe"));
){
// 读写数据
int len;
byte[] bytes = new byte[8*1024];
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0 , len);
}
} catch (IOException e) {
e.printStackTrace();
}
// 记录结束时间
long end = System.currentTimeMillis();
System.out.println("缓冲流使用数组复制时间:"+(end - start)+" 毫秒");
}
}
缓冲流使用数组复制时间:521 毫秒
7.2 字符缓冲流
构造方法
| 方法| 简述|
| --- | --- |
|BufferedReader(Reader in) | 创建使用默认大小的输入缓冲区的缓冲字符输入流。 |
| BufferedWriter(Writer out) |创建使用默认大小的输出缓冲区的缓冲字符输出流。|
构造方法举例。
//通过字符输入流对象,创建字符缓冲对象。
BufferedReader bufferedReader = new BufferedReader(new FileReader("C:\\a.txt"));
//通过字符输出流对象,创建字符缓冲对象。
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("C:\\a.txt"));
字符缓冲流特有方法
字符缓冲流的基本方法与普通字符流调用方式一致,这里不再阐述,我们来看字符缓冲流具备的特有方法。
| 方法| 简述|
| --- | --- |
|BufferedReader:public String readLine() |读一行数据 读取到最后返回null |
|BufferedWriter:`public void newLine() |换行 由系统属性定义符号。|
readLine
方法演示代码如下:
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
// 创建流对象
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
// 定义字符串,保存读取的一行文字
String line = null;
// 循环读取,读取到最后返回null
while ((line = br.readLine())!=null) {
System.out.print(line);
System.out.println("------");
}
// 释放资源
br.close();
}
}
newLine
方法演示代码如下:
public class BufferedWriterDemo throws IOException {
public static void main(String[] args) throws IOException {
// 创建流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
// 写出数据
bw.write("哥");
// 写出换行
bw.newLine();
bw.write("敢");
bw.newLine();
bw.write("摸屎");
bw.newLine();
bw.write("你敢吗?");
bw.newLine();
// 释放资源
bw.close();
}
}
输出效果:
哥
敢
摸屎
你敢吗?
6、序列化流
6.1 什么是序列化?
序列化将对象信息转换为可以存储或者传输的形式的过程。用一个字节序列可以表示一个对象,该字节序列包含该 对象的数据
、对象的类型
和 对象中存储的属性
等信息。字节序列写出到文件中后,就相当于文件中 持久保存了一个对象的信息
。
同时也可以将字节序列从文件中取出,然后再拿到该 对象的数据类型和属性
。
<center>
</center>
6.2 ObjectOutputStream类
java.io.ObjectOutputStream
类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。
构造方法
修饰类型 | 方法 | 简述 |
---|---|---|
protected | ObjectOutputStream() | 为完全重新实现ObjectOutputStream的子类提供一种方法,不必分配刚刚被ObjectOutputStream实现使用的私有数据。 |
ObjectOutputStream(OutputStream out) | 创建一个写入指定的OutputStream的ObjectOutputStream。 |
序列化操作
实现序列化,满足条件:
- 该类必须实现
java.io.Serializable
接口 - 该类的所有属性必须是可序列化的。
- 该类必须实现
1、
Serializable
是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出 NotSerializableException
[/font]2、如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用transient关键字修饰。
示例
public class Personal implements java.io.Serializable{
private String name;
private Integer age;
private transient String Address;
}
写出对象操作
writeObject (Object obj)
: 将指定的对象写出。
public class MainT {
public static void main(String[] args) throws IOException {
//实例化对象
Personal personal = new Personal("JuRan", 12, "四川");
//创建字节流对象
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Personal.txt");
//创建序列化流对象
ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutputStream);
//写出流对象
objectOutput.writeObject(personal);
//关闭资源(先开后关闭)
objectOutput.close();
fileOutputStream.close();
}
}
6.3 ObjectInputStream类
java.io.ObjectInputStream
类,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
构造方法
public ObjectInputStream(InputStream in)
: 创建一个指定InputStream的ObjectInputStream。
反序列化操作一、
Personal personal = null;
//创建字节流对象
FileInputStream fileInputStream = new FileInputStream("C:\\Personal.txt");
//创建序列化流对象
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
//写出流对象
Object o = null;
try {
o = objectInputStream.readObject();
//将对象向下转型获取属性
personal = (Personal) o;
} catch (ClassNotFoundException e) {
System.out.println("对象无法找到ClassNotFundException");
e.printStackTrace();
}
System.out.println(personal.toString());
//关闭资源(先开后关闭)
objectInputStream.close();
fileInputStream.close();
对于JVM可以反序列化对象,它必须是能够找到class文件的类。
如果找不到该类的class文件,则抛出一个
ClassNotFoundException
异常。反序列化操作二、
当我们对class文件进行修改过后,我们再使用反序列化。那么反序列化操作也会失败,抛出一个 InvalidClassException
异常。
发生该异常存在的原因如下
1、该类的序列版本号与从流中读取的类描述符的版本号不匹配
2、该类包含未知数据类型
3、该类没有可访问的无参数构造方法
Serializable
接口给需要序列化的类,提供了一个序列版本号。serialVersionUID
该版本号的目的在于验证序列化的对象和对应类是否版本匹配。
public class Personal implements java.io.Serializable{
// 加入序列版本号
private static final long serialVersionUID = 1L;
private String name;
private Integer age;
//添加新的属性 ,重新编译, 可以反序列化,该属性赋为默认值.**
private transient String Address;
}
7、打印流
7.1 什么是打印流?
提起打印,就会想到 System.out.print()
和 system.out.println()
这两个方法都是将我们所需要查看的信息打印输出到控制台方便我们进行查看。实际上这方法都来自 Java.io.PrintStream
类。JDk开发文档中也说过这样一句话 即 “*能够方便地打印各种数据值的表示。”
打印流分类
- 字符打印流(PrintWriter)
- 字节打印流(PrintStream)
打印流特点
- 只操作目的地,不操作源数据
- 可以操作任意类型的数据
- 如果启动了刷新,再使用Println()的时候,能够进行换行并刷新。
- 可以直接操作文件
哪些流可以操作文件呢?
基本上所有流构造方法,能够接受File及和String类型的参数,一般都拥有操作文件的能力。
7.2 字节输出打印流PrintStream复制文本文件。
//创建缓冲流对象
BufferedReader bufferedReader = new BufferedReader (new FileReader("C:\\a.txt"));
//创建打印流对象
PrintStream printStream = new PrintStream("C:\\printStream.txt");
//读取文件内容。
String line;
while ((line=bufferedReader.readLine()) != null){
//打印流将读取字符串输出到文件中
printStream.print(line);
}
printStream.close();
bufferedReader.close();
7.3 字节输出打印流PrintWriter复制文本文件。
//创建缓冲流对象
BufferedReader bufferedReader = new BufferedReader (new FileReader("C:\\b.txt"));
//创建打印流对象
PrintWriter printWriter = new PrintWriter("C:\\printStream.txt");
//读取文件内容。
String line;
while ((line=bufferedReader.readLine()) != null){
//打印流将读取字符串输出到文件中
printWriter.print(line);
}
printWriter.close();
bufferedReader.close();
8、数据流
还在写……