IO印象笔记

2 篇文章 0 订阅

目录

 

File

io字符流

io字节流

各种应用

键盘录入

文件切割与合并

RandomAccessFile实例

java9改进的对象序列化

对象的引用序列化

java9新增 过滤功能

自定义序列化

transient:修饰属性,序列化时将无视这个变量

版本号


File

  File 对象
 *
 *  //可以将一个已存在的,或者不存在的文件或者目录封装成file对象。

 *    是对文件和目录本身和其包含文件和目录基本信息的描述。
      创建对象只是在内存中,需要中creatnewfile 方法在外存中创建。
 *   
 *   
 *    File f1 = new File("c:\\a.txt");   
 *    File f2 = new File("c:\\","a.txt");   
 *    File f = new File("c:\\");   
 *    File f3 = new File(f,"a.txt");  
 *    File f4 = new File("c:"+File.separator+"abc"+File.separator+"a.txt"); 
 *   
 *     File 方法请见 File 类
 *
 * 过滤器  (类似与比较器。容器使用过滤器中方法进行筛选,其中容器可以通过listFiles方法获得)
 * 用来获取指定类型的内容(文件或目录)。
 * FileFilter  文件对象过滤器 根据传递对象根据对象属性筛选
 * FilenameFilter   文件名称过滤器 根据文件名筛选
 *
 *

 * 递归:


 * 删除完整文件
 * 删除文件用队列结构,删除空文件夹用堆栈结构
 *
 * 文件队列,与堆栈的操作。




package text;



import java.io.File;
import java.util.LinkedList;

public class Demo {

    public static void main(String[] args) {
        File dir = new File("E:\\腾讯游戏");
        Queue11<File> queue = new Queue11<File>();
        Duizhan<File> duizhan = new Duizhan<File>();
        queue.myAdd(dir);
        *
         * File[] files = dir.listFiles(); for (File file : files) { if
         * (file.isDirectory()) { queue.myAdd(file); } else { file.delete(); } }
         *

        **
         * 删除文件中所有文件(不含文件夹)
         *
        while (!queue.isNull()) {
            File deFile = queue.myGet();
            File[] deFiles = deFile.listFiles();
            for (File file : deFiles) {
                if (file.isDirectory()) { // 判断File是文件还是文件夹
                    queue.myAdd(file);
                } else { // 若为文件直接删除。
                    file.delete();
                }

            }
        }

        **
         * 删除所有空文件夹。
         *
        duizhan.myAdd(dir);
        while (!duizhan.isNull()) {
            File deFile = duizhan.myGet();  //取出第一个
            File[] deFiles = deFile.listFiles();
            if (deFiles.length == 0) {     //每次取出都要先判断是否为空,为空则删除文件夹,并从堆栈中删除第一个。
                deFile.delete();
                duizhan.myD();
            } else {                    //  否则遍历其子文件夹
                for (File file : deFiles) {
                    File[] fils = file.listFiles();
                    if (fils.length == 0) {      //如果其子文件夹为空,直接删除文件夹,不寸入堆栈。
                        file.delete();
                    } else {
                        duizhan.myAdd(file);   //否则 存入堆栈。
                    }
                }

            }
        }

    }
}


**
 * 泛型队列,用于删除所有文件。
 * @author YFG
 *
 * @param <E>
 *
class Queue11<E> {
    private LinkedList<E> link;

    public Queue11() {
        link = new LinkedList<E>();
    }

    public void myAdd(E obj) {
        link.addLast(obj);
    }

    public E myGet() {

        return link.removeFirst();
    }

    public boolean isNull() {
        return link.isEmpty();
    }
}
**
 * 泛型堆栈,用于删除所有空文件夹。
 * @author YFG
 *
 * @param <E>
 *
class Duizhan<E> {
    private LinkedList<E> linktoo;

    public Duizhan() {
        linktoo = new LinkedList<E>();
    }

    public void myAdd(E obj) {
        linktoo.addFirst(obj);
    }

    public E myGet() {
        return linktoo.getFirst();
    }

    public void myD() {
        linktoo.removeFirst();
    }

    public boolean isNull() {
        return linktoo.isEmpty();
    }

}

package textvido;
*
 *
 * 递归删除目录
 *

import java.io.File;
import java.io.IOException;

public class Zijieliu {

    public static void main(String[] args) throws IOException {
        / TODO Auto-generated method stub
      File dir = new File("E:\\修改一 - 副本");
      removeDir(dir);


    }
    public  static void removeDir (File dir){
        File[] files = dir.listFiles();
        if(files != null){
            for (File file : files) {
                if(file.isDirectory() && file != null){
                    removeDir(file);
                }else{
                    file.delete();
                }
            }
        }
        dir.delete();   /以上只將子目錄刪除 ,此处将本级目录删除。
    }

}


io字符流

public static void main(String[] args){InputStreamReader isr = new InputStreamReader(new Filereader("地址") "编码表")}
z

转换流 : 实现字节流到字符流的转换,在网络传输中,可使用该流实现对字符串的直接操作,不需要手动转为字节数组,该流内部使用的就是字节流。

字符流:Reader ,Writer 字符流超类 使用字符数组 , 操作的基本单位是字符,而字节流操作的基本单位是字节
OutputstreamWriter : 是 FileWriter 的父类 前者使用自定义编码表编码,后者使用默认的编码表编码
inputStreamReader : 是 Filereader 的父类 前者使用自定义的编码表解码 , 后者使用默认的编码表解码。

InputStreamReader 与 OutputstreamWriter:使用缓冲区进行编码和解码。要指定码表;
创建对象要传递一个文件字节流对象和指定码表,因为底层使用的是字节流进行读取;
字节流和字符流缓冲区的区别: 字节流缓冲区是使用字节数组;字符流缓冲区使用字符数组
编码和解码的过程就发生在字符数组和字节数组转换的过程。因此:此流也称转换流
是字符流和字节流的桥梁。

缓冲区对象:
1. 自己构建缓冲区数组
2.
以给予的缓冲区:原理
使用底层流方法从硬盘上获取数据,并存储在缓冲区中,此缓冲区就是利用 Reader 的read();方法将数据存在字符数组缓冲区中;
此缓冲区被封装不可见;
再通过缓冲区的方法从缓冲区获得具体的字符数据,提高效率
如果通过缓冲区read();方法获取字符存储再另一个容器中,直到督导换行符时,另一个
容器的临时存储数据转成字符串返回,就形成了redline()l;方法。
BufferedReader BufferedWriter 提供了缓冲区的方法。利用已有的流写入和读入数据。
提供各种格式的写入和读入方法;换行方法;newLine() 写入一个行分隔符。
readLine() 读取一个文本行。
BufferedReader bufu = new BufferedReader(new Filereader("地址"));
3.
自定义缓冲区对象:提供更多的缓冲区方法
自己从从新构建 BufferedReader BufferedWriter 类
缓冲区数组也要自己构建并封装,对外不可见。



只有out 和Writer 有刷新
flush();将流中的缓冲区的数据刷新到目的低,刷新后还可以使用
close(); 关闭资源之前刷新一次。
如果写入数据多,一边写一边刷新。最后可以用close();
刷新的目的是及时将数据写出。防止缓冲区未满,由于其他原因流意外关闭造成的数据丢失。
此外缓冲区在满的情况下会自动刷新。

GBK码表: 如果第一个字节为正,就查一个字节:如果第一个是负数,就连续读两个字节;
UTF-8: 三个字节单元;


装饰设计模式:BufferedReader BufferedWriter 都是装饰类
继承 Reader 对其他被装饰子类进行操作,扩展功能。避免继承各子类扩展功能造成的臃肿。
装饰类通常不单独存在,与被装饰类一同存在,提供对外的构造函数接受被装饰类。

io字节流

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;

*
 * 字节流
 * 数据要写入文件中。要先创建文件对象。
 * 创建一个用于操作文件的字节输出流对象,一创建就要明确数据存储的目的
 *
 * 转义字符: \r  在换行符前要加转义字符
 * \r\n  为换行。
 * 使用此类常量,要用system.获取系统常量值代替。
 *
 *
*
 *
 * 输入流与输出流类似与File关联;输出流有write()方法,输入流有read();方法;
 *
 * 磁针读取数据是连续读取,不会跳跃。
 * 字节流写出和读入的数据都是字节数据,需要转换才能获取有效信息。
 * *

public class 字节流 {
    public static void main(String[] args) throws IOException {
        / 数据要写入文件中。要先创建文件对象。
        File file = new File("E:\\ads.txt");

        / 输出流目的是文件,会自动在外存中创建文件。如果存在,则覆盖。此处也打开了文件
        FileOutputStream fos = new FileOutputStream(file);//
        /write();方法输出字节。
    }
}

public class IOExceptionDemo {

    private static final String LINE_SEPARATOR = System.getProperty("line.separator"); // 获得系统换行符。

    public static void main(String[] args) {

        FileOutputStream fw = null;
        try {

            fw = new FileOutputStream("k:\\demo.txt");

            fw.write("abcde".getBytes());

        } catch (IOException e) {
            System.out.println(e.toString());
        } finally {
            if (fw != null)  //如果字符流差个创建失败。
                try {
                    fw.close();    //可能关闭失败
                } catch (IOException e) {
                    / code....
                    throw new RuntimeException("关闭失败");// 此异常无法解决 将异常转换为运行时异常抛出。
                }
        }
    }
}



 *
 * 输入流与输出流类似与File关联;输出流有write()方法,输入流有read();方法;
 *
 * */

各种应用


ObjectOutputStream:
对象序列化: 想要将保存了数据的对象进行持久化,读取更方便。
当写入的很多对象会按照顺序排列,也称为序列化。
ObjectOutputStream(OutputStream out) 是对 OutputStream 的功能扩展
writeObject(Object obj)
静态数据不会被序列化。
对于一个非静态数据也不要被序列化,如密码
可用:transient 瞬态 标记

ObjectInputStream:
反序列化: 对持久化对象中数据的读取。依靠 InputStream,对其进行扩展。
读取对象必须有相应对象的 class
ObjectInputStream(InputStream in)
readObject();
用于防止程序崩溃丢失数据。
Serializable:序列化接口,要序列化的对象必须实现该接口
序列化接口的作用:没有方法,不需要覆盖。是一个标记接口
唯一作用给每一个需要序列话的类分配一个序列版本号
这个版本号和该类相关联。
版本号作用: 验证序列化对象和类是否相同,如有不同抛出异常。
序列化时,版本号也一同存在序列化文件中。
反序列化时会读取版本号进行验证。
可序列化类可以通过声明名为 "serialVersionUID" 的字段
(该字段必须是静态 (static)、最终 (final) 的 long 型字段)
显式声明其自己的 serialVersionUID :
强烈建议 所有可序列化类都显式声明 serialVersionUID 值,
默认版本号容易变动,所以显示给出。就不会因为修饰符而改变。


需求: 将一个整数表现形式不变,写出。
字节打印流: PrintStream
字节流writer方法只将一个整数四个字节中的最后一个写入。
1.将整数转为字符串变成字节数组。
2. PrintStream 方便打印各种数据值的表现形式。
扩展 FileOutputStream 利用 print()进行原样打印。
构造: PrintStream(File file)
PrintStream(OutputStream out)
PrintStream(String fileName)
提供众多打印方法,保证数据的表现形式不变。

字符打印流 PrintWriter : 详情查阅API 含有自动刷新和非自动刷新的构造方法。

需求: 保证数据源字节原样形式的不变。字节不变。
需要可以操作基本数据类型的对象。将数据类型数据写入。
DataOutputStream : 输出基本数据类型的完整字节
DataInputStream : 按照基本数据类型的长短读取并解码。

字节数组流:ByteArrayOutputStream: 写到内部字节数组;
ByteArrayInputStream : 构造时可直接传递字节数组;
利用流的方法对数组进行操作。
没有iO异常,不调用底层资源,不需要关闭流,不会抛出io异常。

需求: 对文件进行读或写的操作。 想从哪读从哪读,想从哪写从哪写。

io 工具类 : RandomAccessFile: 随机访问文件的读取和写入。
1. 随机访问 2. 操作文件 3. 既可以读又可以写。
4. 内部维护了用于存储数据的byte数组。
5.提供了对数组操作的文件指针。
6. 文件 指针可以通过 getFilePointer()方法获取,并通过seek();方法设置
7.要明确指针位置,避免数据混乱。
8. 可以用于多线程
特别是下载。
mode :文件访问方式:
"r" 只读
"rw" 读和写 不存在则创建
"rws"
"rwd"

键盘录入


获取标准输入流: InputStream in = System.in; 键盘录入时字节流。
输入流已打开,不需要关闭,一但关闭,不可打开。
字节流 --> 桥梁 :InputStreamReader -->字符流 实现对字符单位的操作。
InputStreamReader isr = new InputStreamReader(in);
通过缓冲区提高效率 BufferReader buff = new BufferReader(isr);
此时就可以使用缓冲区方法经进行操作。
BufferReader buff = new BufferReader(new InputStreamReader(System.in));三句合一句
键盘录入注意定义结束标记,或强制停止。
line = buff.readLine();键盘输入一行。

文件切割与合并

文件切割:读取文件复制到多个文件中
切割文件方式,按碎片个数,按碎片大小
一个输入流对应多个输出流。
每一个输出流需要编号,顺序不可乱。
File srcFile = new File("src");
File partsDir = new File("partFiles");
splitFile();
pubic static void splitFile(File srcFile, File partsDir){
if(!(srcFile.exists() && srcFile.isFile())){
throw new RuntimeException();
}
if(!partsDir.exists()){
partsDir.mkdirs();
}
1. 字节读取流和源文件关联
FileInputStream fis = new FileInputStream(srcFile);
2. 明确目的。输出流又多个,只创建引用。
FileOutputStream fos = null;
3.定义缓冲区。
byte[] buf = new byte[BUFFER_SIZE];//BUFFER_SIZE = 1048576(1mb)
4.频繁读写操作
int len = 0;
碎片编号
conut = 1;
while((len =fis.read(buf))!=-1){
创建输出流对象,满足缓冲区大小,写入碎片
fos = new FileOutputStream(new File(partsDir,(conut++)+".part"));
fos.writer(buf, 0 , len);
fos.close();
}//
fis.close();
}

文件切割,配置文件的建立和读取
将源文件俺以及切割的信息也保存起来随碎片一发送。
信息: 源文件名称,文件类型。碎片的个数 。封装在一个文件中
还要一个输出流完成此动作。
问题:配置文件过多需要存储,使用map集合键值对,存储信息都是字符串,信息不在内存中,再硬盘上
使用hashmap有泛型,取出需要强转,因此使用 Properties; system 属性就是使用的
Properties ;
很多常用的配置文件都是使用 Properties 存储。
使用:setProperty("string","string");存
getProperty("string"); 取

演示从流中加载和保存的方法(持久化)
File configFle = new File("");
FileReader fr = new FileReader(configFle);
Properties Pror = new Properties();
Pror.load(fr);
在流中加载数据。
FileWriter fw = new FileWriter("规范info.Properties");
Pror.store(fw, "info");
将 Properties 中信息存储在fw流中。




文件合并:多个源多个读取流;多个源的数据都要和同一个输出流关联
多个源---> 一个目的地
代码的问题: 碎片过多,意味着流过多,需要容器先存储起来,操作也更方便
1.需要容器 2. 将流与碎片关联起来存储起来 3. 遍历容器。
使用 list 集合循环存储读取流对象。


SequenceInputStream 将流序列化。
此问题以封装为对象:SequenceInputStream 将多个源合并为一个源。

将读取流遍历存入list
获取枚举对象
Enumeration<FileInputStream> en = Collections.enumeration(list);
枚举传入序列流
SequenceInputStream sis = new SequenceInputStream(en);
sis 为一个序列流可作为一个整体读取数据,和关闭。

在获取配置文件中的信息时, 可以用过滤器获得配置文件,在getProperties.获取配置信息。

RandomAccessFile实例

访问中间部分数据 

public class RandomAccessFileTest
{
	public static void main(String[] args)
	{
		try(
			RandomAccessFile raf =  new RandomAccessFile(
				"RandomAccessFileTest.java" , "r"))
		{
			// 获取RandomAccessFile对象文件指针的位置,初始位置是0
			System.out.println("RandomAccessFile的文件指针的初始位置:"
				+ raf.getFilePointer());
			// 移动raf的文件记录指针的位置
			raf.seek(300);
			byte[] bbuf = new byte[1024];
			// 用于保存实际读取的字节数
			int hasRead = 0;
			// 使用循环来重复“取水”过程
			while ((hasRead = raf.read(bbuf)) > 0 )
			{
				// 取出“竹筒”中水滴(字节),将字节数组转换成字符串输入!
				System.out.print(new String(bbuf , 0 , hasRead ));
			}
		}
		catch (IOException ex)
		{
			ex.printStackTrace();
		}
	}
}

追加内容

public class AppendContent
{
	public static void main(String[] args)
	{
		try(
			//以读、写方式打开一个RandomAccessFile对象
			RandomAccessFile raf = new RandomAccessFile("out.txt" , "rw"))
		{
			//将记录指针移动到out.txt文件的最后
			raf.seek(raf.length());
			raf.write("追加的内容!\r\n".getBytes());
		}
		catch (IOException ex)
		{
			ex.printStackTrace();
		}
	}
}

插入到指定位置

public class InsertContent
{
	public static void insert(String fileName , long pos
		, String insertContent) throws IOException
	{
		File tmp = File.createTempFile("tmp" , null);
		tmp.deleteOnExit();
		try(
			RandomAccessFile raf = new RandomAccessFile(fileName , "rw");
			// 使用临时文件来保存插入点后的数据
			FileOutputStream tmpOut = new FileOutputStream(tmp);
			FileInputStream tmpIn = new FileInputStream(tmp))
		{
			raf.seek(pos);
			// ------下面代码将插入点后的内容读入临时文件中保存------
			byte[] bbuf = new byte[64];
			// 用于保存实际读取的字节数
			int hasRead = 0;
			// 使用循环方式读取插入点后的数据
			while ((hasRead = raf.read(bbuf)) > 0 )
			{
				// 将读取的数据写入临时文件
				tmpOut.write(bbuf , 0 , hasRead);
			}
			// ----------下面代码插入内容----------
			// 把文件记录指针重新定位到pos位置
			raf.seek(pos);
			// 追加需要插入的内容
			raf.write(insertContent.getBytes());
			// 追加临时文件中的内容
			while ((hasRead = tmpIn.read(bbuf)) > 0 )
			{
				raf.write(bbuf , 0 , hasRead);
			}
		}
	}
	public static void main(String[] args)
		throws IOException
	{
		insert("InsertContent.java" , 45 , "插入的内容\r\n");
	}
}

java9改进的对象序列化

  • 必须实现两个接口中的一个 : Seralizable 或  Externallizable 标记其可序列化。z
  • 建议每个JavaBean类都实现Seralizable
  • 反序列化机制无须通过构造器初始化对象
  • 反序列化对象,必须存在该类的class文件
  • 将多个对象写入同一个文件时,反序列化要根据这个顺序读取
  • 一个可序列化类的父类必须是可序列化的,或则有无参数的构造器。否则抛出,IncalidClassException
  • 如果父类不可序列化,只有无参数的构造器,则父类中定义的成员变量不会序列化到二进制流中。
  • 序列化
    public class WriteObject
    {
    	public static void main(String[] args)
    	{
    		try(
    			ObjectOutputStream oos = new ObjectOutputStream(
    				new FileOutputStream("object.txt")))
    		{
    			Person per = new Person("?????", 500);
    			oos.writeObject(per);
    		}
    		catch (IOException ex)
    		{
    			ex.printStackTrace();
    		}
    	}
    }
    
    反序列化
    public class ReadObject
    {
    	public static void main(String[] args)
    	{
    		try(
    			ObjectInputStream ois = new ObjectInputStream(
    				new FileInputStream("object.txt")))
    		{
    			
    			Person p = (Person)ois.readObject();
    			System.out.println("???????" + p.getName()
    				+ "\n???????" + p.getAge());
    		}
    		catch (Exception ex)
    		{
    			ex.printStackTrace();
    		}
    	}
    }

    对象的引用序列化

  • 引用的对象必须是可序列化的,否则该对象不可序列化。
  • 多次序列化同一个对象,只有第一次会输出字节数据,之后只输出序列号。
  • 多个对象引用同一个对象,该对象仅第一次被序列化。
  • 序列化可变对象,仅在第一次会序列化,即使发生改变,也不会再序列化。
  • public class WriteTeacher
    {
    	public static void main(String[] args)
    	{
    		try(
    			// 创建一个ObjectOutputStream输出流
    			ObjectOutputStream oos = new ObjectOutputStream(
    				new FileOutputStream("teacher.txt")))
    		{
    			Person per = new Person("孙悟空", 500);
    			Teacher t1 = new Teacher("唐僧" , per);
    			Teacher t2 = new Teacher("菩提祖师" , per);
    			// 依次将四个对象写入输出流
    			oos.writeObject(t1);
    			oos.writeObject(t2);
    			oos.writeObject(per);
    			oos.writeObject(t2);
    		}
    		catch (IOException ex)
    		{
    			ex.printStackTrace();
    		}
    	}
    }
    
    public class ReadTeacher
    {
    	public static void main(String[] args)
    	{
    		try(
    			// 创建一个ObjectInputStream输出流
    			ObjectInputStream ois = new ObjectInputStream(
    				new FileInputStream("teacher.txt")))
    		{
    			// 依次读取ObjectInputStream输入流中的四个对象
    			Teacher t1 = (Teacher)ois.readObject();
    			Teacher t2 = (Teacher)ois.readObject();
    			Person p = (Person)ois.readObject();
    			Teacher t3 = (Teacher)ois.readObject();
    			// 输出true
    			System.out.println("t1的student引用和p是否相同:"
    				+ (t1.getStudent() == p));
    			// 输出true
    			System.out.println("t2的student引用和p是否相同:"
    				+ (t2.getStudent() == p));
    			// 输出true
    			System.out.println("t2和t3是否是同一个对象:"
    				+ (t2 == t3));
    		}
    		catch (Exception ex)
    		{
    			ex.printStackTrace();
    		}
    	}
    }

    java9新增 过滤功能

  • setObjectInputFilter(ObjectInputFilter filter) ,getObjectInputFilter() 
  • ObjectInputFilter : 函数式接口,可以用lambda代替
  • 反序列化时会自动调用ObjectInputFilter .checkInput(ObjectInputFilter.info info)方法
  • 具体请查阅java9:java9api
  •  

自定义序列化

  • transient:修饰属性,序列化时将无视这个变量

  • public class Person
    	implements java.io.Serializable
    {
    	private String name;
    	private transient int age;
    }
    
    
    public class TransientTest
    {
    	public static void main(String[] args)
    	{
    		try(
    			/ 创建一个ObjectOutputStream输出流
    			ObjectOutputStream oos = new ObjectOutputStream(
    				new FileOutputStream("transient.txt"));
    			/ 创建一个ObjectInputStream输入流
    			ObjectInputStream ois = new ObjectInputStream(
    				new FileInputStream("transient.txt")))
    		{
    			Person per = new Person("孙悟空", 500);
    			/ 系统会per对象转换字节序列并输出
    			oos.writeObject(per);
    			Person p = (Person)ois.readObject();
    			System.out.println(p.getAge());
                     /age = 0;
    		}
    		catch (Exception ex)
    		{
    			ex.printStackTrace();
    		}
    	}
    }

     

  • 替换序列化的属性。正常对person序列化就可以。
public class Person
	implements java.io.Serializable
{
	private String name;
	private int age;
	// 注意此处没有提供无参数的构造器!
	public Person(String name , int age)
	{
		System.out.println("有参数的构造器");
		this.name = name;
		this.age = age;
	}
	// 省略name与age的setter和getter方法

	// name的setter和getter方法
	public void setName(String name)
	{
		this.name = name;
	}
	public String getName()
	{
		return this.name;
	}

	// age的setter和getter方法
	public void setAge(int age)
	{
		this.age = age;
	}
	public int getAge()
	{
		return this.age;
	}

	private void writeObject(java.io.ObjectOutputStream out)
		throws IOException
	{
		// 将name实例变量的值反转后写入二进制流
		out.writeObject(new StringBuffer(name).reverse());
		out.writeInt(age);
	}
	private void readObject(java.io.ObjectInputStream in)
		throws IOException, ClassNotFoundException
	{
		// 将读取的字符串反转后赋给name实例变量
		this.name = ((StringBuffer)in.readObject()).reverse()
			.toString();
		this.age = in.readInt();
	}
}
  • 替换要序列化的对象
  • public class Person
    	implements java.io.Serializable
    {
    	private String name;
    	private int age;
    	// 注意此处没有提供无参数的构造器!
    	public Person(String name , int age)
    	{
    		System.out.println("有参数的构造器");
    		this.name = name;
    		this.age = age;
    	}
    	// 省略name与age的setter和getter方法
    
    	// name的setter和getter方法
    	public void setName(String name)
    	{
    		this.name = name;
    	}
    	public String getName()
    	{
    		return this.name;
    	}
    
    	// age的setter和getter方法
    	public void setAge(int age)
    	{
    		this.age = age;
    	}
    	public int getAge()
    	{
    		return this.age;
    	}
    
    	//	重写writeReplace方法,程序在序列化该对象之前,先调用该方法
    	private Object writeReplace()throws ObjectStreamException
    	{
    		ArrayList<Object> list = new ArrayList<>();
    		list.add(name);
    		list.add(age);
    		return list;
    	}
    }
    
    
    public class ReplaceTest
    {
    	public static void main(String[] args)
    	{
    		try(
    			// 创建一个ObjectOutputStream输出流
    			ObjectOutputStream oos = new ObjectOutputStream(
    				new FileOutputStream("replace.txt"));
    			// 创建一个ObjectInputStream输入流
    			ObjectInputStream ois = new ObjectInputStream(
    				new FileInputStream("replace.txt")))
    		{
    			Person per = new Person("孙悟空", 500);
    			// 系统将per对象转换字节序列并输出
    			oos.writeObject(per);
    			// 反序列化读取得到的是ArrayList
    			ArrayList list = (ArrayList)ois.readObject();
    			System.out.println(list);
    		}
    		catch (Exception ex)
    		{
    			ex.printStackTrace();
    		}
    	}
    }
  • 替换读取到的序列化对象,并丢弃读取到的
  • public class Orientation
    	implements java.io.Serializable
    {
    	public static final Orientation HORIZONTAL = new Orientation(1);
    	public static final Orientation VERTICAL = new Orientation(2);
    	private int value;
    	private Orientation(int value)
    	{
    		this.value = value;
    	}
    	// 为枚举类增加readResolve()方法
    	private Object readResolve()throws ObjectStreamException
    	{
    		if (value == 1)
    		{
    			return HORIZONTAL;
    		}
    		if (value == 2)
    		{
    			return VERTICAL;
    		}
    		return null;
    	}
    }
    
    
    public class ResolveTest
    {
    	public static void main(String[] args)
    	{
    		try(
    
    			ObjectOutputStream oos = new ObjectOutputStream(
    				new FileOutputStream("transient.txt"));
    
    			ObjectInputStream ois = new ObjectInputStream(
    				new FileInputStream("transient.txt")))
    		{
    			oos.writeObject(Orientation.HORIZONTAL);
    			Orientation ori = (Orientation)ois.readObject();
    			System.out.println(ori == Orientation.HORIZONTAL);
    		}
    		catch (Exception ex)
    		{
    			ex.printStackTrace();
    		}
    	}
    }

 

版本号

private static final long serialVersionUID = ****L

最好显示给出,这样即使类发生了改变,也能正常反序列化。因为类一旦改变,jvm自动分配的id将会改变,会认为不是同一个类。

不能正常反序列化的情况: 实例变量更改类型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值