• java之 属性集 & 缓冲流 & 序列化流


    0x01、属性集

    1、Properties类的概述

    java.util.Properties 继承于 Hashtable ,来表示一个持久的属性集。它使用键值结构存储数据,每个键及其对应值都是一个字符串。该类也被许多Java类使用,比如获取系统属性时,System.getProperties 方法就是返回一个Properties对象。加载文件中配置信息等等

    2、Properties类的构造方法

    public Properties()` :创建一个空的属性列表。
    

    3、Properties类存储方法

    public Object setProperty(String key, String value) : 保存一对属性。  
    public String getProperty(String key)  :使用此属性列表中指定的键搜索属性值。
    public Set<String> stringPropertyNames()  :所有键的名称的集合。
    

    示例代码:

    public static void main(String[] args) throws FileNotFoundException {
            // 创建属性集对象
            Properties properties = new Properties();
            // 添加键值对元素
            properties.setProperty("filename", "a.txt");
            properties.setProperty("length", "209385038");
            properties.setProperty("location", "D:\a.txt");
            // 打印属性集对象
            System.out.println(properties);
            // 通过键,获取属性值
            System.out.println(properties.getProperty("filename"));
            System.out.println(properties.getProperty("length"));
            System.out.println(properties.getProperty("location"));
    
            // 遍历属性集,获取所有键的集合
            Set<String> strings = properties.stringPropertyNames();
            // 打印键值对
            for (String key : strings ) {
              	System.out.println(key+" -- "+properties.getProperty(key));
            }
        }
    

    输出结果:

    {filename=a.txt, length=209385038, location=D:a.txt}
    a.txt
    209385038
    D:a.txt
    filename -- a.txt
    length -- 209385038
    location -- D:a.txt
    

    4、Properties类与流相关的方法

    public void load(InputStream inStream): 从字节输入流中读取键值对。
    public void load(Reader reader): 从字节输入流中读取键值对。 
    

    参数中使用了字节输入流,通过流对象,可以关联到某文件上,这样就能够加载文本中的数据了。

    加载代码演示:

    public class Test3 {
        public static void main(String[] args) throws Exception{
            /*
    		 注意:
              1.文本中的数据,必须是键值对形式,可以使用空格、等号、冒号等符号分隔。
              2.如果配置文件中有中文,那么加载文件文件时,使用字符流,但是开发中一般配置文件中不要写中文
             */
            
            // 创建Properties对象
            Properties pro = new Properties();
    
            // 往pro对象中添加键值对
            pro.setProperty("username", "root");
            pro.setProperty("password", "123456");
            pro.setProperty("url", "http://www.baidu.com");
    
            // 把pro对象中的键值对写入到文件中
            FileOutputStream fos = new FileOutputStream("db2.properties");
            pro.store(fos,"itheima");
    
            // 关闭流
            fos.close();
    
    
        }
    

    加载(读取)配置文件中的数据

        private static void method01() throws IOException {
            // 1.加载(读取)配置文件中的数据
            // 创建Properties对象
            Properties pro = new Properties();
    
            // 调用load方法加载配置文件中的数据
            //FileInputStream fis = new FileInputStream("a.txt");
            FileInputStream fis = new FileInputStream("db2.properties");
            pro.load(fis);// 把关联文件中的数据以键值对的形式存储到pro对象中
    
            // 关闭流,释放资源
            fis.close();
    
            // 打印pro对象
            System.out.println(pro);
    
            System.out.println("--------------------------------------------------");
            // 注意事项: 如果配置文件中有中文 使用字符流
            // 创建Properties对象
            Properties pro2 = new Properties();
    
            // 调用load方法加载配置文件中的数据
            FileReader fr = new FileReader("a.txt");
            pro2.load(fr);// 把关联文件中的数据以键值对的形式存储到pro对象中
    
            // 关闭流,释放资源
            fr.close();
    
            // 打印pro对象
            System.out.println(pro2);
        }
    }
    

    0x02、缓冲流

    缓冲流,也叫高效流,是对4个基本的FileXxx 流的增强,所以也是4个流,按照数据类型分类:

    • 字节缓冲流BufferedInputStreamBufferedOutputStream
    • 字符缓冲流BufferedReaderBufferedWriter

    缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。

    1、字节缓冲流

    public BufferedInputStream(InputStream in) :创建一个 新的缓冲输入流。 
    public BufferedOutputStream(OutputStream out): 创建一个新的缓冲输出流。
    

    构造举例,代码如下:

    // 创建字节缓冲输入流
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bis.txt"));
    // 创建字节缓冲输出流
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));
    

    使用缓冲流读写一个字节拷贝文件

    public class BufferedDemo {
        public static void main(String[] args) throws Exception {
           long start = System.currentTimeMillis();
            // 创建字节输入流对象,关联数据源文件路径
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("B_test.exe"));
            // 创建字节输出流对象,关联目的地文件路径
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E_test.exe"));
            // 定义一个int类型的变量,用来存储读取到的字节数据
            int len;
            // 循环读取
            while ((len = bis.read()) != -1) {
                // 在循环中,写出数据
                bos.write(len);
            }
            // 关闭流,释放资源
            bos.close();
            bis.close();
            long end = System.currentTimeMillis();
            System.out.println("总共需要:" + (end - start) + "毫秒");// 大约32秒
        }
    }
    

    使用缓冲流读写一个数组字节拷贝文件

    public class BufferedDemo {
        public static void main(String[] args) throws FileNotFoundException {
            long start = System.currentTimeMillis();
            // 创建字节输入流对象,关联数据源文件路径
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("B_test.exe"));
            // 创建字节输出流对象,关联目的地文件路径
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E_test.exe"));
            // 定义一个字节数组,用来存储读取到的字节数据
            byte[] bys = new byte[8192];
            // 定义一个int类型的变量,用来存储读取到的字节数据
            int len;
            // 循环读取
            while ((len = bis.read(bys)) != -1) {
                // 在循环中,写出数据
                bos.write(bys,0,len);
            }
            // 关闭流,释放资源
            bos.close();
            bis.close();
            long end = System.currentTimeMillis();
            System.out.println("总共需要:" + (end - start) + "毫秒");// 大约4秒
        }
    }
    
    

    0x03、序列化流

    Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据对象的类型对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。

    反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化对象的数据对象的类型对象中存储的数据信息,都可以用来在内存中创建对象。看图理解序列化:

    1、ObjectOutputStream类

    (1)构造方法:

    public ObjectOutputStream(OutputStream out): 创建一个指定OutputStream的ObjectOutputStream。
    

    代码示例:

    FileOutputStream fileOut = new FileOutputStream("employee.txt");
    ObjectOutputStream out = new ObjectOutputStream(fileOut);
    

    一个对象要想序列化,必须满足两个条件:

    • 该类必须实现java.io.Serializable 接口,Serializable 是一个标记接口
    public final void writeObject (Object obj) : 将指定的对象写出。
    

    示例代码:

    public class Test {
        public static void main(String[] args)throws Exception {
            // 创建Student对象
            Student s = new Student("张三", 18);
            // 需求:将s对象写入到 C:\Users\86183\Desktop\ser.txt 文件中
            
            // 创建序列化流对象,关联目的地文件路径
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\Users\86183\Desktop\ser.txt"));
            // 写出对象
            oos.writeObject(s);
            // 关闭流,释放资源
            oos.close();
        }
    }
    

     对象序列化包括如下步骤:

    1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
    2) 通过对象输出流的writeObject()方法写对象。
    

    2、ObjectInputStream类

    ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。

    (1)构造方法

    public ObjectInputStream(InputStream in) : 创建一个指定InputStream的ObjectInputStream
    

    如果能找到一个对象的class文件,我们可以进行反序列化操作,调用ObjectInputStream读取对象的方法:

    public final Object readObject () : 读取一个对象。
    

    示例代码:

    public class Test {
        public static void main(String[] args) throws Exception{
            // 反序列化:读取之前序列化的对象
            // 1.创建反序列化流对象,关联数据源文件路径
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:Users86183Desktopser.txt"));
            // 2.读取一个对象
            Object obj = ois.readObject();
            System.out.println(obj);
            // 3.关闭流,释放资源
            ois.close();
        }
    }
    

    对象反序列化的步骤如下:

    1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
    2) 通过对象输入流的readObject()方法读取对象。
    

    3、小结

      我们可以看到,先通过输入流创建一个文件,再调用ObjectOutputStream类的 writeObject方法`,把序列化的数据写入该文件;

    ​ 然后调用ObjectInputStream类的readObject方法反序列化数据并打印数据内容

    反序列化的注意事项

    • 对于JVM可以反序列化对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个 ClassNotFoundException 异常。

    • 另外,当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException异常。发生这个异常的原因如下:

      • 该类的序列版本号与从流中读取的类描述符的版本号不匹配
      • 该类包含未知数据类型
      • 该类没有可访问的无参数构造方法

    Serializable 接口给需要序列化的类,提供了一个序列版本号。serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

  • 相关阅读:
    Python Day7(相关补充)
    Python Day7
    Python Day6
    Python Day5
    Python Day4
    Python Day3
    Python Day2
    Python Day1
    复杂装饰器原理分析
    Unity 坐标
  • 原文地址:https://www.cnblogs.com/0x7e/p/14320472.html
Copyright © 2020-2023  润新知