ioObjectAndProperties

一、       ObjectOutputStreamAndObjectInputStream

使用ObjectOutputStream和ObjectInputStream实现对象的读写操作。一般,将对象写出到文件,称为序列化流;将具有对象内容的文件读入到内存,称为反序列化流。

1.       序列化流

java.io
类 ObjectOutputStream

java.lang.Object

  java.io.OutputStream

      java.io.ObjectOutputStream

所有已实现的接口: Closeable, DataOutput,Flushable, ObjectOutput, ObjectStreamConstants

public class ObjectOutputStream

extends OutputStream

implements ObjectOutput,ObjectStreamConstants

ObjectOutputStream 将Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。

只能将支持 java.io.Serializable 接口的对象写入流中。每个 serializable 对象的类都被编码,编码内容包括类名和类签名、对象的字段值和数组值,以及从初始对象中引用的其他所有对象的闭包。

writeObject 方法用于将对象写入流中。所有对象(包括 String 和数组)都可以通过 writeObject 写入。可将多个对象或基元写入流中。必须使用与写入对象时相同的类型和顺序从相应 ObjectInputstream 中读回对象。

还可以使用 DataOutput 中的适当方法将基本数据类型写入流中。还可以使用 writeUTF 方法写入字符串。

对象的默认序列化机制写入的内容是:对象的类,类签名,以及非瞬态和非静态字段的值。其他对象的引用(瞬态和静态字段除外)也会导致写入那些对象。可使用引用共享机制对单个对象的多个引用进行编码,这样即可将对象的图形恢复为最初写入它们时的形状。

例如,要写入可通过 ObjectInputStream 中的示例读取的对象,请执行以下操作:

       FileOutputStream fos = new FileOutputStream("t.tmp");

        ObjectOutputStreamoos = new ObjectOutputStream(fos);

       oos.writeInt(12345);

       oos.writeObject("Today");

       oos.writeObject(new Date());

       oos.close();

在序列化和反序列化过程中需要特殊处理的类必须实现具有下列准确签名的特殊方法:

 private voidreadObject(java.io.ObjectInputStream stream)

     throwsIOException, ClassNotFoundException;

 private voidwriteObject(java.io.ObjectOutputStream stream)

     throwsIOException

 private voidreadObjectNoData()

     throwsObjectStreamException;

writeObject 方法负责写入特定类的对象状态,以便相应的 readObject 方法可以恢复它。该方法本身不必与属于对象的超类或子类的状态有关。状态是通过使用 writeObject 方法或使用 DataOutput 支持的用于基本数据类型的方法将各个字段写入 ObjectOutputStream 来保存的。

序列化操作不写出没有实现 java.io.Serializable 接口的任何对象的字段。不可序列化的 Object 的子类可以是可序列化的。在此情况下,不可序列化的类必须有一个无参数构造方法,以便允许初始化其字段。在此情况下,子类负责保存和恢复不可序列化的类的状态。经常出现的情况是,该类的字段是可访问的(public、package 或protected),或者存在可用来恢复状态的 get 和set 方法。

在 writeObject 和 readObject 方法的实现中抛出 NotSerializableException,可以阻止对象的序列化。ObjectOutputStream将捕获异常并中止序列化进程。

实现 Externalizable 接口允许对象假定可以完全控制对象的序列化形式的内容和格式。调用 Externalizable 接口的方法(writeExternal 和 readExternal)来保存和恢复对象的状态。通过类实现时,它们可以使用ObjectOutput 和 ObjectInput 的所有方法读写它们自己的状态。对象负责处理出现的任何版本控制。

Enum 常量的序列化不同于普通的serializable 或 externalizable 对象。enum 常量的序列化形式只包含其名称;常量的字段值不被传送。为了序列化 enum 常量,ObjectOutputStream 需要写入由常量的名称方法返回的字符串。与其他serializable 或 externalizable 对象一样,enum 常量可以作为序列化流中后续出现的 back 引用的目标。用于序列化 enum 常量的进程不可定制;在序列化期间,由 enum 类型定义的所有类特定的 writeObject 和 writeReplace 方法都将被忽略。类似地,任何 serialPersistentFields 或 serialVersionUID 字段声明也将被忽略,所有 enum 类型都有一个 0L 的固定的serialVersionUID。

基本数据(不包括 serializable 字段和externalizable 数据)以块数据记录的形式写入 ObjectOutputStream 中。块数据记录由头部和数据组成。块数据部分包括标记和跟在部分后面的字节数。连续的基本写入数据被合并在一个块数据记录中。块数据记录的分块因子为 1024 字节。每个块数据记录都将填满 1024 字节,或者在终止块数据模式时被写入。调用 ObjectOutputStream 方法 writeObject、defaultWriteObject 和 writeFields 最初只是终止所有现有块数据记录。

从以下版本开始: JDK1.1

另请参见: DataOutput, ObjectInputStream,Serializable,Externalizable,SerializationSpecification, Section 2, Object Output Classes

Method

 void

writeObject(Object obj)
          将指定的对象写入 ObjectOutputStream。

注意:对象的序列化需要对象的类实现Serializable接口。

例子:

创建序列化类

public class Person implements Serializable{

   private staticfinallongserialVersionUID = 1L;

   private Stringname;

   private intage;

   private Stringaddress;

   public Person() {

      super();

   }

   public Person(Stringname,intage,Stringaddress){

      super();

      this.name =name;

      this.age =age;

      this.address =address;

   }

   public String getName() {

      return name;

   }

   public voidsetName(String name){

      this.name =name;

   }

   public intgetAge() {

      return age;

   }

   public voidsetAge(intage){

      this.age =age;

   }

   public String getAddress() {

      return address;

   }

   public voidsetAddress(String address){

      this.address =address;

   }

   @Override

   public String toString() {

      return "Person [name=" + name + ", age="+ age+ ", address=" + address+ "]";

   }

}

将类对象写出到文件

public class ObjectOutputTest {

   public staticvoidmain(String[] args)throwsFileNotFoundException, IOException{

      Person p=new Person("看看",11,"看看了");

      ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("oos.txt"));

      oos.writeObject(p);

      oos.close();

   }

}

2.       反序列化流

java.io
类 ObjectInputStream

java.lang.Object

  java.io.InputStream

      java.io.ObjectInputStream

所有已实现的接口: Closeable, DataInput,ObjectInput, ObjectStreamConstants

public class ObjectInputStream

extends InputStream

implements ObjectInput,ObjectStreamConstants

ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。

ObjectOutputStream 和ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久存储。ObjectInputStream用于恢复那些以前序列化的对象。其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。

ObjectInputStream 确保从流创建的图形中所有对象的类型与 Java 虚拟机中显示的类相匹配。使用标准机制按需加载类。

只有支持 java.io.Serializable 或java.io.Externalizable 接口的对象才能从流读取。

readObject 方法用于从流读取对象。应该使用 Java 的安全强制转换来获取所需的类型。在 Java 中,字符串和数组都是对象,所以在序列化期间将其视为对象。读取时,需要将其强制转换为期望的类型。

可以使用 DataInput 上的适当方法从流读取基本数据类型。

默认情况下,对象的反序列化机制会将每个字段的内容恢复为写入时它所具有的值和类型。反序列化进程将忽略声明为瞬态或静态的字段。对其他对象的引用使得根据需要从流中读取这些对象。使用引用共享机制能够正确地恢复对象的图形。反序列化时始终分配新对象,这样可以避免现有对象被重写。

读取对象类似于运行新对象的构造方法。为对象分配内存并将其初始化为零 (NULL)。为不可序列化类调用无参数构造方法,然后从以最接近 java.lang.object 的可序列化类开始和以对象的最特定类结束的流恢复可序列化类的字段。

例如,要从由 ObjectOutputStream 中的示例写入的流读取:

        FileInputStreamfis = new FileInputStream("t.tmp");

       ObjectInputStream ois = new ObjectInputStream(fis);

        int i =ois.readInt();

        Stringtoday = (String) ois.readObject();

        Date date =(Date) ois.readObject();

       ois.close();

类控制实现 java.io.Serializable 或java.io.Externalizable 接口时的序列化方式。

实现 Serializable 接口允许对象序列化,以保存和恢复对象的全部状态,并且允许类在写入流时的状态和从流读取时的状态之间变化。它自动遍历对象之间的引用,保存和恢复全部图形。

在序列化和反序列化进程中需要特殊处理的 Serializable 类应该实现以下方法:

 private voidwriteObject(java.io.ObjectOutputStream stream)

     throwsIOException;

 private voidreadObject(java.io.ObjectInputStream stream)

     throwsIOException, ClassNotFoundException;

 private voidreadObjectNoData()

     throwsObjectStreamException;

readObject 方法负责使用通过对应的 writeObject 方法写入流的数据,为特定类读取和恢复对象的状态。该方法本身的状态,不管是属于其超类还是属于其子类,都没有关系。恢复状态的方法是,从个别字段的 ObjectInputStream 读取数据并将其分配给对象的适当字段。DataInput支持读取基本数据类型。

尝试读取由对应的 writeObject 方法写入的超出自定义数据边界的对象数据将导致抛出 OptionalDataException(eof 字段值为 true)。超出已分配数据末尾的非对象读取以指示流末尾的方式反映数据结束:按位读取与字节读取或字节数读取一样,将返回 -1,基元读取将抛出 EOFException。如果不存在对应的 writeObject 方法,则默认的序列化数据的末尾标记已分配数据的末尾。

从 readExternal 方法发出的基元和对象读取调用的行为方式一样:如果流已经定位在由相应 writeExternal 方法写入的数据末尾,则对象读取将抛出OptionalDataException(其 eof 设置为true),按位读取将返回 -1,基元读取将抛出EOFException。注意,此行为不适用于使用旧 ObjectStreamConstants.PROTOCOL_VERSION_1协议写入的流,在这些流中,没有划分出由 writeExternal 方法写入的数据末尾,因此无法检测。

如果序列化流没有将给定类列为要反序列化的对象的超类,则 readObjectNoData 方法负责初始化其特定类的对象状态。在接收方使用的反序列化实例类的版本不同于发送方,并且接收者版本扩展的类不是发送者版本扩展的类时,此事可能发生。如果序列化流已经被篡改,也会发生这种情况;因此,不管源流是“敌意的”还是不完整的,readObjectNoData方法都可以用来正确地初始化反序列化的对象。

对于没有实现 java.io.Serializable 接口的任何对象,序列化不会对其字段进行读取或赋值。非 serializable 的 Object 的子类可以为 serializable。在此情况下,非 serializable 类必须具有无参数的构造方法以允许其字段能被初始化。在此情况下,子类负责保存和恢复非 serializable 类的状态。经常出现的情况是,该类的字段是可访问的(public、package 或 protected),或者存在可用于恢复状态的 get 和 set 方法。

反序列化对象进程中发生的所有异常将由 ObjectInputStream 捕获并将中止读取进程。

实现 Externalizable 接口允许对象假定可以完全控制对象的序列化形式的内容和格式。调用 Externalizable 接口的方法(writeExternal 和 readExternal)来保存和恢复对象状态。当这两种方法被某个类实现时,它们可以使用 ObjectOutput 和 ObjectInput 的所有方法读写其本身的状态。对象负责处理出现的任何版本控制。

Enum 常量的反序列化不同于普通的serializable 或 externalizable 对象。Enum 常量的序列化形式只包含其名称;不传送常量的字段值。要反序列化 enum 常量,ObjectInputStream 需要从流中读取常量的名称;然后将 enum 常量的基本类型和接收到的常量名称作为参数,调用静态方法Enum.valueOf(Class, String) 获取反序列化的常量。与其他 serializable 或 externalizable 对象一样,enum 常量可以作为序列化流中随后出现的反向引用的目标。不可以自定义 enum 常量的反序列化进程:在反序列化期间,enum 类型所定义的任何与类有关的 readObject、readObjectNoData 和 readResolve 方法都将被忽略。类似地,任何 serialPersistentFields 或 serialVersionUID 字段声明也将被忽略(所有 enum 类型都有一个固定的 0L 的serialVersionUID)。

从以下版本开始: JDK1.1

另请参见: DataInput, ObjectOutputStream,Serializable,对象序列化规范:Object Input Classes 第三节

Method

 Object

readObject()
          从 ObjectInputStream 读取对象。

注意:反序列化过程中,要保证对象类的序列号与写出到文件时的序列号一致。如果,写出后,修改了对象类的序列号,则报无效类异常。

例子:

创建类略

将序列化的类文件读入到内存

public class ObjectInputTest {

   public staticvoidmain(String[] args)throwsFileNotFoundException, IOException, ClassNotFoundException{

      ObjectInputStream ois=new ObjectInputStream(new FileInputStream("oos.txt"));

      Person p=(Person)ois.readObject();

      System.out.println(p.getName()+"--"+p.getAddress());

      ois.close();

   }

}

二、       Properties

java.util
类 Properties

java.lang.Object

  java.util.Dictionary<K,V>

      java.util.Hashtable<Object,Object>

          java.util.Properties

所有已实现的接口: Serializable, Cloneable,Map<Object,Object>

直接已知子类: Provider

public class Properties

extends Hashtable<Object,Object>

Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。

一个属性列表可包含另一个属性列表作为它的“默认值”;如果未能在原有的属性列表中搜索到属性键,则搜索第二个属性列表。

因为 Properties 继承于 Hashtable,所以可对Properties 对象应用 put 和 putAll 方法。但不建议使用这两个方法,因为它们允许调用者插入其键或值不是 String的项。相反,应该使用 setProperty 方法。如果在“不安全”的 Properties 对象(即包含非 String 的键或值)上调用 store 或 save 方法,则该调用将失败。类似地,如果在“不安全”的 Properties 对象(即包含非 String 的键)上调用 propertyNames 或 list 方法,则该调用将失败。

load(Reader)/ store(Writer,String) 方法按下面所指定的、简单的面向行的格式在基于字符的流中加载和存储属性。除了输入/输出流使用 ISO 8859-1 字符编码外,load(InputStream)/store(OutputStream,String) 方法与 load(Reader)/store(Writer, String) 对的工作方式完全相同。可以使用Unicode转义来编写此编码中无法直接表示的字符;转义序列中只允许单个 'u' 字符。可使用 native2ascii 工具对属性文件和其他字符编码进行相互转换。

loadFromXML(InputStream)storeToXML(OutputStream,String, String) 方法按简单的 XML 格式加载和存储属性。默认使用 UTF-8 字符编码,但如果需要,可以指定某种特定的编码。XML 属性文档具有以下 DOCTYPE 声明:

 <!DOCTYPEproperties SYSTEM "http://java.sun.com/dtd/properties.dtd">

注意,导入或导出属性时 访问系统 URI(http://java.sun.com/dtd/properties.dtd);该系统 URI 仅作为一个唯一标识 DTD 的字符串:

    <?xmlversion="1.0" encoding="UTF-8"?>

    <!-- DTD forproperties -->

    <!ELEMENTproperties ( comment?, entry* ) >

    <!ATTLISTproperties version CDATA #FIXED "1.0">

    <!ELEMENTcomment (#PCDATA) >

    <!ELEMENTentry (#PCDATA) >

    <!ATTLISTentry key CDATA #REQUIRED>

从以下版本开始: JDK1.0

另请参见: native2asciitool for Solaris,native2asciitool for Windows 此类是线程安全的:多个线程可以共享单个 Properties 对象而无需进行外部同步。,序列化表格

Method

1.       使用map类似的方法来操作Properties。

父类Dictionary的方法

abstract  V

put(K key,V value)
          将指定 key 映射到此 dictionary 中指定 value。

父类Hashtable的方法

 Set<K>

keySet()
          返回此映射中包含的键的 Set 视图。

   public voidtest1(){

      Properties p=new Properties();

      p.put("hh看","考2虑");

      p.put("hh2看","考4虑");

      p.put("h2h看","考2虑");

      p.put("hhd看","考3虑");

      Set set=p.keySet();

      for(Objecto:set){

         System.out.println(o+"--"+p.get(o));

      }

   }

2.       使用Properties特有的方式操作数据

 String

getProperty(String key)
          用指定的键在此属性列表中搜索属性。

 String

getProperty(String key)
          用指定的键在此属性列表中搜索属性。

 Set<String>

stringPropertyNames()
          返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键。

   public voidtest2(){

      Properties p=new Properties();

      p.setProperty("kk流量","上述");

      p.setProperty("kk2流量","上3述");

      p.setProperty("k3k流量","上2述");

      Set<String> s=p.stringPropertyNames();

      for(Iteratori=s.iterator();i.hasNext();){

         String key=(String)i.next();

         System.out.println(key+"--"+p.getProperty(key));

      }

      for(Stringss:s){

         System.out.println(ss+"--"+p.getProperty(ss));

      }

   }

3.       Properties与流相关的操作

 void

store(OutputStream out,String comments)
          以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。

 void

load(InputStream inStream)

例子:

写出到文件

   public voidtest3() throws FileNotFoundException,IOException{

      Properties p=new Properties();

      p.setProperty("kk流量","上述");

      p.setProperty("kk2流量","上3述");

      p.setProperty("k3k流量","上2述");

      p.store(newFileOutputStream("prop.txt"),"哈哈哈");

   }

读入到内存

   public voidtest4() throwsFileNotFoundException, IOException{

      Properties p=new Properties();

      p.load(new FileInputStream("prop.txt"));

      System.out.println(p.getProperty("prop"));

      Set<String> s=p.stringPropertyNames();

      for(Stringss:s){

         System.out.println(ss+"--"+p.getProperty(ss));

      }

   }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值