zoukankan      html  css  js  c++  java
  • IO流:对象流、Poperties类

    1、对象流OjectInputStream和ObjecOutputStream
       可以用它来实现对象的序列化和反序列化,但读写的对象必须实现Serializable序列化接口
       对象的输出流将指定的对象写入到文件的过程,就是将对象序列化的过程,对象的输入流将指定序列化好的文件读出来的过程,就是对象反序列化的过程
       
       常用构造方法:
       ObjectOutputStream oos = new ObjectOutputStream(OutputStream out);//创建一个写入指定OutputStream的ObjectOutputStream对象.   
       ObjectInputStream ois = new ObjectInputStream(InputStream in);//创建从指定 InputStream 读取的 ObjectInputStream

       public class Student implements Serializable{
        /**
         *但是,如果这时候这个obj.txt是我们项目中一个文件,而项目到后期在原来Student类的基础上添加成员变量String sex;   
         *private int id;
         *private String name;
         *private int age;
         *private String sex;//新添加成员变量
         *这时候如果我们再反序列化,则会引发异常:java.io.InvalidClassException: xuliehua.User; local class incompatible: stream classdesc serialVersionUID = 2161776237447595412, local class serialVersionUID = -3634244984882257127
         *serialVersionUID 是用于记录class文件的版本信息的,serialVersionUID这个数字是JVM(JAVA虚拟界)通过一个类的类名、成员、包名、工程名算出的一个数字。
         *    而这时候序列化文件中记录的serialVersionUID与项目中的不一致,即找不到对应的类来反序列化
         *如果序列化与反序列化的时候可能会修改类的成员,那么最好一开始就给这个类指定一个serialVersionUID,如果一类已经指定的serialVersionUID,然后
         *    在序列化与反序列化的时候,jvm都不会再自己算这个 class的serialVersionUID了
         */
        private static final long serialVersionUID = 1L;

        private int id;
        private String name;
        private int 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;
        }
        public Student(int id, String name, int age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }
        public Student() {
        }
        public String toString() {
            return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
        }
       }

       public class ObjectInputStream {

        public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
            //序列化
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:\test\test02.txt"));
            oos.writeObject(new Student(1,"小明",24));
            oos.writeObject(new Student(2,"小张",25));
            oos.writeObject(new Student(3,"小李",26));
            oos.writeObject(new Student(4,"小王",27));
            oos.writeObject(new Student(5,"小吕",28));
            oos.close();
            //反序列化
            java.io.ObjectInputStream ois = new java.io.ObjectInputStream(new FileInputStream("d:\test\test02.txt"));
            Object o = null;
            while((o = ois.readObject())!=null) {
                Student s = (Student)o;
                System.out.println(s);
            }
            ois.close();
        }

    }

       写入文件内容:
    � sr IOObject.Student       I ageI idL namet Ljava/lang/String;xp     t 灏忔槑sq ~       t 灏忓紶sq ~       t 灏忔潕sq ~       t 灏忕帇sq ~       t 灏忓悤
       
       运行打印内容:
    Student [id=1, name=小明, age=24]
    Student [id=2, name=小张, age=25]
    Student [id=3, name=小李, age=26]
    Student [id=4, name=小王, age=27]
    Student [id=5, name=小吕, age=28]
    反序列化时抛出java.io.EOFException异常

    问题描述:在反序列化对象时,当对象出入流将文件的全部类反序列化之后,始终会抛出java.io.EOFException.

    原因:java API文档中对于反序列化对象时使用的java.io.ObjectInputStream类的readObject()方法的描述有一句话是"该方法始终会抛出异常",也就是说该异常无法避免的.

    解决方法:

      该异常是输入流已经到结尾了的标志,我们可以将其捕获,然后不做任何操作,即结束了该次反序列化操作

       public class ObjectStreamTest {
     
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            FileOutputStream out = new FileOutputStream("test3.txt");
            ObjectOutputStream outputStream = new ObjectOutputStream(out);
            outputStream.writeObject(new Student("魏金浩" , 23, 138896));
            outputStream.close();
            Student i;
            FileInputStream in = new FileInputStream("test3.txt");
            ObjectInputStream inputStream = new ObjectInputStream(in);
            i = (Student)inputStream.readObject();//容易造成异常的发生,可能读取超界
            System.out.println(i);
            inputStream.close();
        }
       }
       优化代码:
       public static void main(String[] args) throws IOException, ClassNotFoundException {
            FileOutputStream out = new FileOutputStream("test3.txt");
            ObjectOutputStream outputStream = new ObjectOutputStream(out);
            ArrayList<Student> a = new ArrayList<>();
            a.add(new Student("魏金浩" , 23, 138896));
            outputStream.writeObject(a);
            outputStream.close();
            ArrayList<Student> b;
            FileInputStream in = new FileInputStream("test3.txt");
            ObjectInputStream inputStream = new ObjectInputStream(in);
            b = (ArrayList)inputStream.readObject();//我们只需要读取一次所以不会造成越界
            inputStream.close();
            for (Student student : b) {
                System.out.println(student);
            }
       }


       transient关键字:
       当你不想要某些字段序列化时候,可以用transient关键字修饰
        private int id;
        private String name;
        private int age;
        private transient String sex;//新添加的成员变量//添加关键字transient后,序列化时忽略

       总结:

       1. 如果对象需要被写出到文件上,那么对象所属的类必须要实现Serializable接口。 Serializable接口没有任何的方法,是一个标识接口而已。
       2. 对象的反序列化创建对象的时候并不会调用到构造方法的。
       3. serialVersionUID 是用于记录class文件的版本信息的,serialVersionUID这个数字是通过一个类的类名、成员、包名、工程名算出的一个数字。
       4. 使用ObjectInputStream反序列化的时候,ObjeectInputStream会先读取文件中的serialVersionUID,然后与本地的class文件的serialVersionUID进行对比,如果这两个id不一致,反序列则失败。
       5. 如果序列化与反序列化的时候可能会修改类的成员,那么最好一开始就给这个类指定一个serialVersionUID,如果一类已经指定的serialVersionUID,然后在序列化与反序列化的时候,jvm都不会再自己算这个 class的serialVersionUID了。
       6. 如果一个对象某个数据不想被序列化到硬盘上,可以使用关键字transient修饰。
       7. 如果一个类维护了另外一个类的引用,则另外一个类也需要实现Serializable接口。

    2、Poperties类

       Java中有个比较重要的类Properties(Java.util.Properties),主要用于读取Java的配置文件,各种语言都有自己所支持的配置文件,配置文件中很多变量是经常改变的,这样做也是为了方便用户,让用户能够脱离程序本身去修改相关的变量设置
       在Java中,其配置文件常为.properties文件,格式为文本文件,文件的内容的格式是“键=值”的格式,文本注释信息可以用"#"来注释。
       
       主要的方法:
    1. getProperty ( String key),用指定的键在此属性列表中搜索属性。也就是通过参数 key ,得到 key 所对应的 value。

    2. load ( InputStream inStream),从输入流中读取属性列表(键和元素对)。通过对指定的文件(比如说上面的 test.properties 文件)进行装载来获取该文件中的所有键 - 值对。以供 getProperty ( String key) 来搜索。

    3. setProperty ( String key, String value) ,调用 Hashtable 的方法 put 。他通过调用基类的put方法来设置 键 - 值对。

    4. store ( OutputStream out, String comments),以适合使用 load 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。与 load 方法相反,该方法将键 - 值对写入到指定的文件中去。

    5. clear (),清除所有装载的 键 - 值对。该方法在基类中提供。

       Java读取Properties文件
       最常用的还是通过java.lang.Class类的getResourceAsStream(String name)方法来实现,如下可以这样调用:
       InputStream in = getClass().getResourceAsStream("资源Name");

       或者下面这种也常用:
       InputStream in = new BufferedInputStream(new FileInputStream(filepath));
       综合实例:
       public class PopertyTest {

        public static void main(String[] args) throws IOException {
            Properties pp = new Properties();
            //读取文件中的信息并写入Properties
            FileInputStream f = new FileInputStream("a.poperties");
            pp.load(f);
            String s = pp.getProperty("name");
            System.out.println(s);
            //返回Properties表中的键的Set集合
            Set<String > set = pp.stringPropertyNames();
            Iterator<String> it = set.iterator();
            while(it.hasNext()) {
                String ss= it.next();
                System.out.println(ss+"="+pp.getProperty(ss));
            }
            
            FileOutputStream fos = new FileOutputStream("a.poperties");
            //增加Properties中的属性
            pp.setProperty("sex", "女");
            //将此 Properties 表中的属性列表(键和元素对)写入输出流  
            pp.store(fos, "alfj");
        }
       }

  • 相关阅读:
    Roman to Integer
    Remove Element
    Maximum Subarray
    Climbing Stairs
    Binary Tree Preorder Traversal
    C++引用和指针
    adb
    Traceview
    解析xml
    SDK manager 下载不同版本sdk
  • 原文地址:https://www.cnblogs.com/snzd9958/p/9637121.html
Copyright © 2011-2022 走看看