13.3 IO流
13.3.1 IO流作用和分类
三、IO流
1、IO流的作用
数据无论是写到文件、还是发送到网络、还是其他目的地,只要有数据的输出,就必须用到IO流。
或者从文件读取、从网络接收、从其他数据源(键盘输入),只要有数据的读取,也必须使用IO流。
Scanner input = new Scanner(System.in)
System.out.println()
即IO流用了读、写数据。
2、IO流的分类
(1)按照方向分:
输入流: ==> read(),next(),nextInt()
从其他地方到当前的程序,参照物是当前的程序。
从键盘输入数据到当前程序,System.in 输入流
从文件中读取数据到当前程序,FileInputStream 输入流
....
输出流 ==> write/print
从当前程序到控制台,System.out 输出流
从当前程序把数据写到文件中,相当于输出到磁盘,FileOutputStream 输出流
(2)按照处理数据的方式、单位不同
字节流:以字节为单位,最小可以处理1个字节
字符流:以字符为单位,最小可以处理1个字符
1个字符可能是1~4个字节,和具体的编码方式以及和当前字符的编码值有关。
字符流只能处理纯文本数据,即字符串。
字节流可以处理任意类型的数据。包括基本数据类型、字符串、图片、音频、视频等。
(3)按照IO流的角色不同
节点流:例如文件是一个数据的节点,网络终端(网页、数据库、服务器等)也是一个数据的结点,内存中一个字节数组、字符数组都可以是数据的节点。
处理流(也称为装饰流):对IO流操作的一个装饰作用,
例如:缓冲流(提高读写效率)
对象流(对对象进行序列化和反序列化)
转换流(对文本进行解码和编码)
所有的IO流操作必须要有节点流,但是处理流可以没有,如果有对数据更加复杂的操作要求,需要加1~n个处理流。
3、无论是那种分类,都是从4个最基本的基类中派生出去
(1)InputStream ==>所有字节输入流的父类
(2)OutputStream ==>所有字节输出流的父类
(3)Reader ==>所有字符输入流的父类
(4)Writer ==>所有字符输出流的父类
节点流:
FileInputStream、FileOutputStream、FileReader、FileWriter ==>操作文件
ByteArrayInputStream、ByteArrayOutputStream ==>操作字节数组
CharArrayReader、CharArrayWriter ==>操作字符数组
StringReader、StringWriter ==>操作字符串
其余:
BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter ==>缓冲流
InputStreamReader ==>把字节数据转为字符数据 解码
OutputStreamWriter ==>把字符数据转为字节数据 编码
ObjectInputStream 、ObjectOutpuStream
13.3.2 文件IO流
一、文件IO流
FileInputStream:文件字节输入流,以字节为单位从文件中读取数据到当前程序
FileOutputStream:文件字节输出流,以字节为单位把数据写到文件中,保存到文件中
FileReader:文件字符输入流,以字符为单位从纯文本文件中读取数据到当前程序
FileWriter:文件字符输出流,以字符为单位把当前程序中的数据写到纯文本文件中
1、FileWriter
1、FileWriter:文件字符输出流
步骤:
(1)先创建一个IO流对象
FileWriter fw = new FileWriter("aaa.txt")
(2)输出数据:调用write
fw.write("我们下周JavaSE就要学完了!")
(3)关闭资源
fw.close()
A:输出时,这个文件不存在,会自动创建。
B:如果该IO流对象,后面还要用,当前数据想要及时出去,就要用flush
C:默认FileWriter是覆盖模式,如果输出之前,文件已存在,新输出的内容会覆盖原来的文件
如果要追加输出的话,需要在创建FileWriter对象时,指定用追加模式。
FileWriter fw = new FileWriter("aaa.txt",true)
D:FileWriter对应的需要是一个文件,而且最好是个纯文本文件。不能是文件夹。
什么是纯文本文件?
.txt,.java, .css, .js, .html等
import org.junit.Test;
import java.io.FileWriter;
import java.io.IOException;
public class TestFileWriter {
@Test
public void test1() throws IOException {
FileWriter fw = new FileWriter("aaa.txt");
fw.write("我们下周JavaSE就要学完了!1");
fw.close();
}
@Test
public void test2() throws IOException {
FileWriter fw = new FileWriter("aaa.txt");
fw.write("我们下周JavaSE就要学完了!2");
fw.flush();
fw.write("hello");
fw.close();
}
@Test
public void test3() throws IOException {
FileWriter fw = new FileWriter("aaa.txt",true);
fw.write("我们下周JavaSE就要学完了!3");
fw.close();
}
@Test
public void test4() throws IOException {
FileWriter fw = new FileWriter("atguigu");
fw.write("hello");
fw.close();
}
@Test
public void test5() throws IOException {
FileWriter fw = new FileWriter("chai.jpg");
fw.write("beautiful");
fw.close();
}
}
2、FileReader
2、FileReader:读
步骤:
(1)先创建一个IO流对象
FileReader fr = new FileReader("aaa.txt")
(2)输出数据:调用write
fr.read()
fr.read(char[] data):一次读取data.length个,如果流中没有data.length个字符,有几个读取几个,如果已经到达流末尾,返回-1
返回本次读取的字符数量。
(3)关闭资源
fr.close()
A:读取文件时,如果文件不存在,会报FileNotFoundException
B:FileReader 对应的需要是一个文件,而且最好是个纯文本文件。 不能是文件夹。
import org.junit.Test;
import java.io.FileReader;
import java.io.IOException;
public class TestFileReader {
@Test
public void test1() throws IOException {
FileReader fr = new FileReader("aaa.txt");
System.out.println(fr.read());
System.out.println((char)fr.read());
fr.close();
}
@Test
public void test2(){
System.out.println((int)'我');
}
@Test
public void test3() throws IOException {
FileReader fr = new FileReader("atguigu.txt");
while(true){
int code = fr.read();
if(code == -1){
break;
}
System.out.print((char)code);
}
fr.close();
}
@Test
public void test4() throws IOException {
FileReader fr = new FileReader("aaa.txt");
char[] data = new char[10];
int len;
while((len = fr.read(data)) != -1){
System.out.println("本次:" + len);
System.out.println(new String(data,0,len));
}
fr.close();
}
}
3、FileInputStream:
步骤:
(1)先创建一个IO流对象
FileInputStream fis = new FileInputStream("iotest/aaa.txt");
(2)读取数据:调用read
int read():一次读取一个字节,返回读取的字节值,如果已经到达流末尾,继续读,返回-1
int read(byte[] data):一次读取多个字节,最多读取data.length个字节,返回本次读取的字节数量,如果已经到达流末尾,继续读,返回-1
读取的数据放到了data数组中,这个数据往往是一个重复使用的数组。
(3)关闭资源
fis.close()
import org.junit.Test;
import java.io.FileInputStream;
import java.io.IOException;
public class TestFileInputStream {
@Test
public void test1() throws IOException {
FileInputStream fis = new FileInputStream("iotest/aaa.txt");
System.out.println(fis.read());
fis.close();
}
@Test
public void test2(){
System.out.println((int)'中');
}
@Test
public void test3() throws IOException {
FileInputStream fis = new FileInputStream("iotest/aaa.txt");
byte[] data = new byte[10];
int len;
while((len = fis.read(data)) != -1){
System.out.print(new String(data,0,len));
}
fis.close();
}
}
4、FileOutputStream
4、FileOutputStream:
步骤:
(1)先创建一个IO流对象
FileOutputStream fos = new FileOutputStream("iotest/aaa.txt")
(2)输出数据:调用write
fos.write(字节数组)
(3)关闭资源
fos.close()
package com.atguigu.file;
import org.junit.Test;
import java.io.FileOutputStream;
import java.io.IOException;
public class TestFileOutputStream {
@Test
public void test1() throws IOException {
FileOutputStream fos = new FileOutputStream("iotest/aaa.txt");
fos.write("大家注意了,别睡着了!".getBytes());
fos.close();
}
}
5、文件复制
import java.io.*;
public class FileTools {
public static void forceDir(File dir){
if(dir.isDirectory()){
File[] allSubFile = dir.listFiles();
for (File sub : allSubFile) {
forceDir(sub);
}
}
dir.delete();
}
public static long getDirectoryLength(File dir){
if(dir != null && dir.isFile()){
return dir.length();
}else if(dir != null && dir.isDirectory()){
long sum = 0;
File[] allSubFile = dir.listFiles();
if(allSubFile != null) {
for (File sub : allSubFile) {
sum += getDirectoryLength(sub);
}
}
return sum;
}
return 0;
}
public static void copyFile(File srcFile, File destFile) throws IOException {
if(srcFile == null || destFile == null){
return;
}
if(srcFile.isDirectory() || destFile.isDirectory()){
return;
}
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
byte[] data = new byte[1024*1024*1024];
int len;
while((len = fis.read(data)) != -1){
fos.write(data, 0 ,len);
}
fos.close();
fis.close();
}
}
import org.junit.Test;
import java.io.File;
import java.io.IOException;
public class TestFileTools {
@Test
public void test1() throws IOException {
File srcFile = new File("iotest/集合框架图.jpg");
File destFile = new File("d:/集合.jpg");
FileTools.copyFile(srcFile,destFile);
}
@Test
public void test2() throws IOException {
File srcFile = new File("iotest/day0403_04哈希值.avi");
File destFile = new File("d:/集合.avi");
FileTools.copyFile(srcFile,destFile);
}
}
6、文件夹复制(了解)
import java.io.*;
public class FileTools {
public static void copyFile(File srcFile, File destFile) throws IOException {
if(srcFile == null || destFile == null){
return;
}
if(srcFile.isDirectory() || destFile.isDirectory()){
return;
}
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
byte[] data = new byte[1024*8];
int len;
while((len = fis.read(data)) != -1){
fos.write(data, 0 ,len);
}
fos.close();
fis.close();
}
public static void copyFileToDirectory(File srcFile, File destDir) throws IOException {
if(srcFile == null || destDir == null){
return;
}
if(srcFile.isDirectory() || destDir.isFile()){
return;
}
if(!destDir.exists()){
destDir.mkdirs();
}
File destFile = new File(destDir, srcFile.getName());
copyFile(srcFile, destFile);
}
public static void copyDirectory(File srcDir, File destDir) throws IOException {
if(srcDir == null || destDir == null){
return;
}
if(srcDir.isFile() && destDir.isFile()){
copyFile(srcDir,destDir);
}else if(srcDir.isFile() && destDir.isDirectory()){
copyFileToDirectory(srcDir,destDir);
}else if(srcDir.isDirectory() && destDir.isFile()){
return;
}else if(srcDir.isDirectory() && destDir.isDirectory()){
File dir = new File(destDir, srcDir.getName());
dir.mkdir();
File[] allSubFiles = srcDir.listFiles();
for (File sub : allSubFiles) {
copyDirectory(sub, dir);
}
}
}
}
@Test
public void test3() throws IOException {
File srcFile = new File("iotest/集合框架图.jpg");
File destDir = new File("d:/");
FileTools.copyFileToDirectory(srcFile,destDir);
}
@Test
public void test4() throws IOException {
File srcDir = new File("D:\Download");
File destDir = new File("D:\temp");
FileTools.copyDirectory(srcDir,destDir);
}
7、文件夹剪切(了解)
import java.io.*;
public class FileTools {
public static void copyFile(File srcFile, File destFile) throws IOException {
if(srcFile == null || destFile == null){
return;
}
if(srcFile.isDirectory() || destFile.isDirectory()){
return;
}
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
byte[] data = new byte[1024*8];
int len;
while((len = fis.read(data)) != -1){
fos.write(data, 0 ,len);
}
fos.close();
fis.close();
}
public static void copyFileToDirectory(File srcFile, File destDir) throws IOException {
if(srcFile == null || destDir == null){
return;
}
if(srcFile.isDirectory() || destDir.isFile()){
return;
}
if(!destDir.exists()){
destDir.mkdirs();
}
File destFile = new File(destDir, srcFile.getName());
copyFile(srcFile, destFile);
}
public static void copyDirectory(File srcDir, File destDir) throws IOException {
if(srcDir == null || destDir == null){
return;
}
if(srcDir.isFile() && destDir.isFile()){
copyFile(srcDir,destDir);
}else if(srcDir.isFile() && destDir.isDirectory()){
copyFileToDirectory(srcDir,destDir);
}else if(srcDir.isDirectory() && destDir.isFile()){
return;
}else if(srcDir.isDirectory() && destDir.isDirectory()){
File dir = new File(destDir, srcDir.getName());
dir.mkdir();
File[] allSubFiles = srcDir.listFiles();
for (File sub : allSubFiles) {
copyDirectory(sub, dir);
}
}
}
public static void cutDirectory(File srcDir, File destDir) throws IOException {
if(srcDir == null || destDir == null){
return;
}
if(srcDir.isFile() && destDir.isFile()){
copyFile(srcDir,destDir);
}else if(srcDir.isFile() && destDir.isDirectory()){
copyFileToDirectory(srcDir,destDir);
}else if(srcDir.isDirectory() && destDir.isFile()){
return;
}else if(srcDir.isDirectory() && destDir.isDirectory()){
File dir = new File(destDir, srcDir.getName());
dir.mkdir();
File[] allSubFiles = srcDir.listFiles();
for (File sub : allSubFiles) {
cutDirectory(sub, dir);
}
}
srcDir.delete();
}
}
@Test
public void test5() throws IOException {
File srcDir = new File("D:\Download_副本");
File destDir = new File("D:\temp");
FileTools.cutDirectory(srcDir,destDir);
}
13.3.3 缓冲流
1、缓冲IO流的类型:
BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter
2、缓冲IO流的作用
(1)最基本的作用:给IO流增加缓冲效应,提高效率
(2)BufferedReader、BufferedWriter可以给字符流增加一个辅助的功能,可以按行读、写
3、注意
(1)缓冲流无法独立使用,必须依赖于其他的IO流,例如文件IO流等
(2)BufferedInputStream只能包装和处理InputStream系列的IO流
BufferedOutputStream只能包装和处理OutputStream系列的IO流
BufferedReader只能包装和处理Reader系列的IO流
BufferedWriter只能包装和处理Writer系列的IO流
import org.junit.Test
import java.io.*
public class TestBufferedInputAndOutputStream {
@Test
public void test1() throws IOException {
FileInputStream fis = new FileInputStream("iotest/aa.txt")
BufferedInputStream bis = new BufferedInputStream(fis)
FileOutputStream fos = new FileOutputStream("iotest/aa_副本.txt")
BufferedOutputStream bos = new BufferedOutputStream(fos)
//iotest/atguigu.txt ==> fis => bis ==> data ==> bos ==> fos ==> iotest/atguigu_副本.txt
byte[] data = new byte[10]
int len
while((len = bis.read(data)) != -1){
bos.write(data,0,len)
}
bos.close()
fos.close()
bis.close()
fis.close()
}
@Test
public void test2() throws IOException {
FileReader fr = new FileReader("iotest/aa.txt")
BufferedReader br = new BufferedReader(fr)
FileWriter fw = new FileWriter("iotest/aa_副本.txt")
BufferedWriter bw = new BufferedWriter(fw)
//iotest/atguigu.txt ==> fr => br ==> line ==> bw ==> fw ==> iotest/atguigu_副本.txt
String line
while((line = br.readLine()) != null){
bw.write(line)
bw.newLine()
}
bw.close()
fw.close()
br.close()
fr.close()
}
}
import java.io.*;
public class FileTools {
public static void copyFileNoBuffer(File srcFile, File destFile) throws IOException {
if(srcFile == null || destFile == null){
return;
}
if(srcFile.isDirectory() || destFile.isDirectory()){
return;
}
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
byte[] data = new byte[1024*8];
int len;
while((len = fis.read(data)) != -1){
fos.write(data, 0 ,len);
}
fos.close();
fis.close();
}
public static void copyFile(File srcFile, File destFile) throws IOException {
if(srcFile == null || destFile == null){
return;
}
if(srcFile.isDirectory() || destFile.isDirectory()){
return;
}
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos =new BufferedOutputStream(fos);
byte[] data = new byte[1024];
int len;
while((len = bis.read(data)) != -1){
bos.write(data, 0 ,len);
}
bos.close();
bis.close();
fos.close();
fis.close();
}
}
@Test
public void test6() throws IOException {
File srcFile = new File("iotest/day0403_04哈希值.avi")
File destFile = new File("d:/集合1.avi")
long start = System.currentTimeMillis()
FileTools.copyFileNoBuffer(srcFile,destFile)
long end = System.currentTimeMillis()
System.out.println("耗时:" + (end-start))
}
@Test
public void test7() throws IOException {
File srcFile = new File("iotest/day0403_04哈希值.avi")
File destFile = new File("d:/集合2.avi")
long start = System.currentTimeMillis()
FileTools.copyFile(srcFile,destFile)
long end = System.currentTimeMillis()
System.out.println("耗时:" + (end-start))
}
13.3.4 转换流
1、转换流
InputStreamReader:把字节数据转为字符数据,也称为解码IO流
OutputStreamWriter:把字符数据转为字节数据,也称为编码IO流
2、转换流的使用
(1)它俩不能独立使用,必须包装其他IO流使用
(2)它们仅限于操作纯文本数据
import org.junit.Test
import java.io.*
public class TestInputStreamReader {
@Test
public void test1()throws IOException {
//文件:iotest/1.txt,它的文件编码是GBK
//当前程序的编码是UTF-8
FileInputStream fis = new FileInputStream("iotest/1.txt")
InputStreamReader isr = new InputStreamReader(fis,"GBK")
//iotest/1.txt ==> fis(里面是字节流,GBK编码的字节流) ==>isr,转换,按照GBK进行解码==> 字符
char[] data = new char[10]
int len
while((len = isr.read(data)) != -1){
System.out.println(new String(data,0,len))
}
isr.close()
fis.close()
}
@Test
public void test2()throws IOException{
//文件:iotest/1.txt,它的文件编码是GBK
//当前程序的编码是UTF-8
FileInputStream fis = new FileInputStream("iotest/1.txt")
BufferedInputStream bis = new BufferedInputStream(fis)
InputStreamReader isr = new InputStreamReader(bis,"GBK")
BufferedReader br = new BufferedReader(isr)
//iotest/1.txt ==> fis(里面是字节流,GBK编码的字节流)==>bis(字节流) ==>isr,转换,按照GBK进行解码==> 字符==>br==>按行读
String str
while((str = br.readLine()) != null){
System.out.println(str)
}
br.close()
isr.close()
bis.close()
fis.close()
}
}
import org.junit.Test;
import java.io.*;
public class TestOutputStreamWriter {
@Test
public void test1()throws IOException {
FileWriter fw = new FileWriter("iotest/1.txt",true);
fw.write("尚硅谷");
fw.close();
}
@Test
public void test2()throws IOException {
FileOutputStream fos = new FileOutputStream("iotest/1.txt",true);
OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK");
osw.write("尚硅谷");
osw.close();
fos.close();
}
@Test
public void test3()throws IOException {
FileOutputStream fos = new FileOutputStream("iotest/1.txt",true);
BufferedOutputStream bos = new BufferedOutputStream(fos);
OutputStreamWriter osw = new OutputStreamWriter(bos,"GBK");
BufferedWriter bw = new BufferedWriter(osw);
bw.newLine();
bw.write("练习");
bw.newLine();
bw.close();
osw.close();
bos.close();
fos.close();
}
}
13.3.5 对象流
1、对象流读和写基本数据类型
两个对象IO流:
1、ObjectInputStream
2、ObjectOutputStream:输出各种数据类型的数据
作用:
1、读或写“基本数据类型”的各种数据
2、读或写引用数据类型的“对象”
注意:
1、它们不能独立使用,必须依赖于其他的IO流。
2、建议保存的文件后缀名自己命名,不要与现有的文件类型相同。
3、用ObjectInputStream读数据的顺序需要与用ObjectOutputStream写数据的顺序一致。
import org.junit.Test
import java.io.*
public class TestObject {
@Test
public void test1()throws IOException {
String name = "巫师"
int age = 300
char gender = '男'
int energy = 5000
double price = 75.5
boolean relive = true
//把上面的数据保存到一个文件中,之后重新读取到程序中使用
FileOutputStream fos = new FileOutputStream("iotest/game.txt")
// fos.write(int),fos.write(byte[])处理不了其他的数据类型
FileWriter fw = new FileWriter("iotest/game.txt")
fw.write(name)
fw.write(age+"")
fw.write(gender+"")
fw.write(energy+"")
fw.write(price+"")
fw.write(relive+"")
fw.close()
}
@Test
public void test2()throws IOException{
FileReader fr = new FileReader("iotest/game.txt")
char[] data = new char[10]
int len
while((len = fr.read(data)) != -1){
//如何区分每一项数据,占几个字符
}
fr.close()
}
@Test
public void test3()throws IOException {
String name = "巫师"
int age = 300
char gender = '男'
int energy = 5000
double price = 75.5
boolean relive = true
FileOutputStream fos = new FileOutputStream("iotest/game.aaa")
ObjectOutputStream oos = new ObjectOutputStream(fos)
oos.writeUTF(name)
oos.writeInt(age)
oos.writeChar(gender)
oos.writeInt(energy)
oos.writeDouble(price)
oos.writeBoolean(relive)
oos.close()
fos.close()
}
@Test
public void test4()throws IOException{
//比喻:自己的解码工具,播放器才能识别里面的数据
//所以,建议使用ObjectOutputStream输出的文件数据,后缀名不要使用.txt等现有的文件的扩展名
FileInputStream fis = new FileInputStream("iotest/game.aaa")
ObjectInputStream ois = new ObjectInputStream(fis)
//读的使用要注意,顺序与写的时候完全一致
String str = ois.readUTF()
int age = ois.readInt()
char c = ois.readChar()
int en = ois.readInt()
double d = ois.readDouble()
boolean b = ois.readBoolean()
System.out.println(str)
System.out.println(age)
System.out.println(c)
System.out.println(en)
System.out.println(d)
System.out.println(b)
ois.close()
fis.close()
}
}
2、对象序列化与反序列化
两个对象IO流:
1、ObjectInputStream
2、ObjectOutputStream:输出各种数据类型的数据
作用:
1、读或写“基本数据类型”的各种数据
2、读或写引用数据类型的“对象”
注意:
1、它们不能独立使用,必须依赖于其他的IO流。
2、建议保存的文件后缀名自己命名,不要与现有的文件类型相同。
3、用ObjectInputStream读数据的顺序需要与用ObjectOutputStream写数据的顺序一致。
4、如果要用ObjectOutputStream输出引用数据类型的对象,要求该对象的类型必须实现java.io.Serializable接口
对象的序列化:把Java对象转为字节数据输出,序列化的IO流:ObjectOutputStream
对象的反序列化:把字节数据“重构”成一个Java对象,反序列化的IO流:ObjectInputStream
import java.io.Serializable;
public class Student implements Serializable {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "name=" + name +", age=" + age;
}
}
@Test
public void test5()throws IOException{
Student stu = new Student("小刘", 25)
FileOutputStream fos = new FileOutputStream("iotest/stu.aaa")
ObjectOutputStream oos = new ObjectOutputStream(fos)
oos.writeObject(stu)
oos.close()
fos.close()
}
@Test
public void test6() throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("iotest/stu.aaa")
ObjectInputStream ois = new ObjectInputStream(fis)
/*
readObject方法可能发生ClassNotFoundException异常
*/
Object obj = ois.readObject()
System.out.println(obj)
ois.close()
fis.close()
}
3、序列化版本ID
两个对象IO流:
1、ObjectInputStream
2、ObjectOutputStream:输出各种数据类型的数据
作用:
1、读或写“基本数据类型”的各种数据
2、读或写引用数据类型的“对象”
注意:
1、它们不能独立使用,必须依赖于其他的IO流。
2、建议保存的文件后缀名自己命名,不要与现有的文件类型相同。
3、用ObjectInputStream读数据的顺序需要与用ObjectOutputStream写数据的顺序一致。
4、如果要用ObjectOutputStream输出引用数据类型的对象,要求该对象的类型必须实现java.io.Serializable接口
对象的序列化:把Java对象转为字节数据输出,序列化的IO流:ObjectOutputStream
对象的反序列化:把字节数据“重构”成一个Java对象,反序列化的IO流:ObjectInputStream
5、当某个类实现了Serializable接口之后,如果没有明确指定“序列化版本ID”,
那么每次修改类重新编译后都会自动产生1个新的“序列化版本ID”,
如果类描述信息中的“序列化版本ID”不一致,是无法正确的反序列化的。
解决:
必须给实现了Serializable接口的类(例如Student类)确定一个“序列化版本ID”。
“序列化版本ID”必须是private static final long serialVersionUID
“序列化版本ID”的值为多少合适呢?
(1)情况一:如果是第一次实现Serializable接口,该类的对象还没有被序列化过,那么“序列化版本ID”写什么值都可以。
(2)情况二:之前已经实现Serializable接口,该类的对象已经被序列化过了,那么要让“序列化版本ID”和上一次序列化时的版本ID值一致
例如:当我们修改了Student类之后,用这段程序重新读之前的stu.aaa文件,发生了如下异常:
java.io.InvalidClassException(无效的类异常):
com.atguigu.object.Student; (Student类)
local class incompatible:(本地的 类 不兼容,不匹配)
stream classdesc serialVersionUID = 7049296973331162856, (流中的类描述信息中的序列化版本ID) (上次序列化的版本ID值)
local class serialVersionUID = -1502441291691716068(本地的类描述信息中序列化版本ID)
import java.io.Serializable;
public class Student implements Serializable {
private int id;
private String name;
private int age;
private static final long serialVersionUID = 7049296973331162856L;
public Student(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "id="+ id +
",name=" + name +
", age=" + age
}
}
@Test
public void test7() throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("iotest/stu.aaa")
ObjectInputStream ois = new ObjectInputStream(fis)
/*
当我们修改了Student类之后,用这段程序重新读之前的stu.aaa文件,发生了如下异常:
java.io.InvalidClassException(无效的类异常):
com.atguigu.object.Student
local class incompatible:(本地的 类 不兼容,不匹配)
stream classdesc serialVersionUID = 7049296973331162856, (流中的类描述信息中的序列化版本ID)
local class serialVersionUID = -1502441291691716068(本地的类描述信息中序列化版本ID)
解决版本:给Student类加了
private static final long serialVersionUID = 7049296973331162856L
*/
Object obj = ois.readObject()
System.out.println(obj)
ois.close()
fis.close()
}
4、static和transient不序列化
1、它们不能独立使用,必须依赖于其他的IO流。
2、建议保存的文件后缀名自己命名,不要与现有的文件类型相同。
3、用ObjectInputStream读数据的顺序需要与用ObjectOutputStream写数据的顺序一致。
4、如果要用ObjectOutputStream输出引用数据类型的对象,要求该对象的类型必须实现java.io.Serializable接口
对象的序列化:把Java对象转为字节数据输出,序列化的IO流:ObjectOutputStream
对象的反序列化:把字节数据“重构”成一个Java对象,反序列化的IO流:ObjectInputStream
5、当某个类实现了Serializable接口之后,如果没有明确指定“序列化版本ID”,
那么每次修改类重新编译后都会自动产生1个新的“序列化版本ID”,
如果类描述信息中的“序列化版本ID”不一致,是无法正确的反序列化的。
解决:
必须给实现了Serializable接口的类(例如Student类)确定一个“序列化版本ID”。
“序列化版本ID”必须是private static final long serialVersionUID
“序列化版本ID”的值为多少合适呢?
(1)情况一:如果是第一次实现Serializable接口,该类的对象还没有被序列化过,那么“序列化版本ID”写什么值都可以。
(2)情况二:之前已经实现Serializable接口,该类的对象已经被序列化过了,那么要让“序列化版本ID”和上一次序列化时的版本ID值一致
例如:当我们修改了Student类之后,用这段程序重新读之前的stu.aaa文件,发生了如下异常:
java.io.InvalidClassException(无效的类异常):
com.atguigu.object.Student; (Student类)
local class incompatible:(本地的 类 不兼容,不匹配)
stream classdesc serialVersionUID = 7049296973331162856, (流中的类描述信息中的序列化版本ID) (上次序列化的版本ID值)
local class serialVersionUID = -1502441291691716068(本地的类描述信息中序列化版本ID)
6、对象序列化,顾名思义,只针对“对象的实例变量”,不会针对类的“静态变量”,因为“静态变量”不属于某个对象,是属于类的。
结论:static修饰的变量值不会被序列化
7、不是对象的所有属性/实例变量值都要进行序列化的,例如对象中临时数据,敏感数据等不需要序列化。
总结:static和transient修饰的成员变量不会序列化。
import java.io.Serializable;
public class Student implements Serializable {
private int id;
private String name;
private transient int age;
private static final long serialVersionUID = 7049296973331162856L;
private static String school;
public Student(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public static String getSchool() {
return school;
}
public static void setSchool(String school) {
Student.school = school;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "id="+ id +
",name=" + name +
", age=" + age +
",school = " + school;
}
}
@Test
public void test8()throws IOException{
Student stu = new Student(1,"李", 25)
Student.setSchool("小学")
FileOutputStream fos = new FileOutputStream("iotest/stu.aaa")
ObjectOutputStream oos = new ObjectOutputStream(fos)
oos.writeObject(stu)
oos.close()
fos.close()
}
@Test
public void test9() throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("iotest/stu.aaa")
ObjectInputStream ois = new ObjectInputStream(fis)
Object obj = ois.readObject()
System.out.println(obj)
ois.close()
fis.close()
}
5、学生问题:自定义序列化规则(不用掌握)
import java.io.Serializable;
public class Student implements Serializable {
private int id;
private String name;
private transient int age;
private static final long serialVersionUID = 7049296973331162856L;
private static String school;
public Student(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public static String getSchool() {
return school;
}
public static void setSchool(String school) {
Student.school = school;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "id="+ id +
",name=" + name +
", age=" + age +
",school = " + school;
}
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
s.writeUTF(school);
s.writeInt(age);
s.writeUTF(name);
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
school = s.readUTF();
age = s.readInt();
name = s.readUTF();
}
}
@Test
public void test8()throws IOException{
Student stu = new Student(1,"李", 25)
Student.setSchool("小学")
FileOutputStream fos = new FileOutputStream("iotest/stu.aaa")
ObjectOutputStream oos = new ObjectOutputStream(fos)
oos.writeObject(stu)
oos.close()
fos.close()
}
@Test
public void test9() throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("iotest/stu.aaa")
ObjectInputStream ois = new ObjectInputStream(fis)
Object obj = ois.readObject()
System.out.println(obj)
ois.close()
fis.close()
}
13.4 IO流关闭顺序
import org.junit.Test;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class TestClose {
@Test
public void test1() throws IOException {
FileWriter fw = new FileWriter("iotest/2.txt");
BufferedWriter bw = new BufferedWriter(fw);
bw.write("hello");
}
@Test
public void test2() throws IOException {
FileWriter fw = new FileWriter("iotest/2.txt");
BufferedWriter bw = new BufferedWriter(fw);
bw.write("hello");
fw.close();
bw.close();
}
@Test
public void test3() throws IOException {
FileWriter fw = new FileWriter("iotest/2.txt");
BufferedWriter bw = new BufferedWriter(fw);
bw.write("hello");
bw.close();
fw.close();
}
@Test
public void test4() throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("iotest/2.txt"));
bw.write("hello");
bw.close();
}
}
13.5 IO流异常处理
JDK1.7版本,引入try-catch的新形式:
try(需要自动关闭的资源对象的声明和初始化){
可能发生异常的业务逻辑代码
}catch(异常的类型 e){
处理异常的代码
}finally{
释放资源之外的其他必须执行的代码
或在try()之外声明的资源的释放代码
}
注意:
放到try()中声明和初始化的资源类必须实现AutoCloseable或Closeable接口。
在try()中声明的资源默认是final修饰的。
package com.atguigu.close;
import java.io.Closeable;
import java.io.IOException;
public class MyClose implements Closeable {
@Override
public void close() throws IOException {
}
}
import org.junit.Test;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class TestTryCatch {
@Test
public void test1() {
FileWriter fw = null;
BufferedWriter bw = null;
try {
fw = new FileWriter("iotest/2.txt");
bw = new BufferedWriter(fw);
bw.write("hello");
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void test2() {
try( FileWriter fw = new FileWriter("iotest/2.txt");
BufferedWriter bw = new BufferedWriter(fw);) {
bw.write("hello");
}catch (IOException e){
e.printStackTrace();
}
}
@Test
public void test3(){
try(MyClose my = new MyClose();){
}catch (Exception e){
}
}
}