• 缓冲流、转换流、序列化流、打印流


    一、缓冲流

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

    字节缓冲流

    • public BufferedInputStream(InputStream in) :创建一个 新的缓冲输入流。
    • public BufferedOutputStream(OutputStream out): 创建一个新的缓冲输出流。
     
    效率测试,缓冲流(最佳)
    public class BufferedDemo {
        public static void main(String[] args) throws FileNotFoundException {
              // 记录开始时间
            long start = System.currentTimeMillis();
            // 创建流对象
            try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("jdk9.exe"));
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.exe"));
            ){
                  // 读写数据
                int len;
                byte[] bytes = new byte[8*1024];
                while ((len = bis.read(bytes)) != -1) {
                    bos.write(bytes, 0 , len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 记录结束时间
            long end = System.currentTimeMillis();
            System.out.println("缓冲流使用数组复制时间:"+(end - start)+" 毫秒");
        }
    }
    缓冲流使用数组复制时间:666 毫秒
     

    字符缓冲流

    • public BufferedReader(Reader in) :创建一个 新的缓冲输入流。
    • public BufferedWriter(Writer out): 创建一个新的缓冲输出流。
     
    • BufferedReader:public String readLine(): 读一行文字。
    • BufferedWriter:public void newLine(): 写一行行分隔符,由系统属性定义符号。
     

    练习:文本排序

    1. 逐行读取文本信息。
    2. 解析文本信息到集合中。
    3. 遍历集合,按顺序,写出文本信息。
    public class BufferedTest {
        public static void main(String[] args) throws IOException {
            // 创建map集合,保存文本数据,键为序号,值为文字
            HashMap<String, String> lineMap = new HashMap<>();
    
            // 创建流对象
            BufferedReader br = new BufferedReader(new FileReader("in.txt"));
            BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));
    
            // 读取数据
            String line  = null;
            while ((line = br.readLine())!=null) {
                // 解析文本
                String[] split = line.split("\.");
                // 保存到集合
                lineMap.put(split[0],split[1]);
            }
            // 释放资源
            br.close();
    
            // 遍历map集合
            for (int i = 1; i <= lineMap.size(); i++) {
                String key = String.valueOf(i);
                // 获取map中文本
                String value = lineMap.get(key);
                  // 写出拼接文本
                bw.write(key+"."+value);
                  // 写出换行
                bw.newLine();
            }
            // 释放资源
            bw.close();
        }
    }

    二、转换流

    编码:字符(能看懂的)--字节(看不懂的)
    解码:字节(看不懂的)-->字符(能看懂的)
     
    ASCII字符集 、ISO-8859-1字符集、GB2312字符集、GBK、Unicode字符集
     

    InputStreamReader类

    • InputStreamReader(InputStream in): 创建一个使用默认字符集的字符流。
    • InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流。
     

    OutputStreamWriter类

    • OutputStreamWriter(OutputStream in): 创建一个使用默认字符集的字符流。
    • OutputStreamWriter(OutputStream in, String charsetName): 创建一个指定字符集的字符流。
     

    练习:转换文件编码

    1. 指定GBK编码的转换流,读取文本文件。
    2. 使用UTF-8编码的转换流,写出文本文件。
    public class TransDemo {
       public static void main(String[] args) {      
            // 1.定义文件路径
             String srcFile = "file_gbk.txt";
            String destFile = "file_utf8.txt";
            // 2.创建流对象
            // 2.1 转换输入流,指定GBK编码
            InputStreamReader isr = new InputStreamReader(new FileInputStream(srcFile) , "GBK");
            // 2.2 转换输出流,默认utf8编码
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(destFile));
            // 3.读写数据
            // 3.1 定义数组
            char[] cbuf = new char[1024];
            // 3.2 定义长度
            int len;
            // 3.3 循环读取
            while ((len = isr.read(cbuf))!=-1) {
                // 循环写出
                  osw.write(cbuf,0,len);
            }
            // 4.释放资源
            osw.close();
            isr.close();
          }
    }

    三、序列化流

     
    用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
    反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据、对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象。
     

    ObjectOutputStream

    • public ObjectOutputStream(OutputStream out): 创建一个指定OutputStream的ObjectOutputStream。
    • public final void writeObject (Object obj) : 将指定的对象写出。
     
    一个对象要想序列化,必须满足两个条件:
    1. 该类必须实现java.io.Serializable 接口,Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException 。
    2. 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用transient 关键字修饰。
    public class Employee implements java.io.Serializable {
        public String name;
        public String address;
        public transient int age; // transient瞬态修饰成员,不会被序列化
        public void addressCheck() {
              System.out.println("Address  check : " + name + " -- " + address);
        }
    }

    ObjectInputStream

    ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
    • public ObjectInputStream(InputStream in): 创建一个指定InputStream的ObjectInputStream。
    • public final Object readObject () : 读取一个对象。
     
    1. 对于JVM可以反序列化对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个 ClassNotFoundException 异常。
    2. 当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException异常。
     
    Serializable 接口给需要序列化的类,提供了一个序列版本号。serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。
    public class Employee implements java.io.Serializable {
         // 加入序列版本号
         private static final long serialVersionUID = 1L;
         public String name;
         public String address;
         // 添加新的属性 ,重新编译, 可以反序列化,该属性赋为默认值.
         public int eid; 
    
         public void addressCheck() {
             System.out.println("Address  check : " + name + " -- " + address);
         }
    }

    练习:序列化集合

    1. 把若干学生对象 ,保存到集合中。
    2. 把集合序列化。
    3. 反序列化读取时,只需要读取一次,转换为集合类型。
    4. 遍历集合,可以打印所有的学生信息
    public class SerTest {
        public static void main(String[] args) throws Exception {
            // 创建 学生对象
            Student student = new Student("老王", "laow");
            Student student2 = new Student("老张", "laoz");
            Student student3 = new Student("老李", "laol");
    
            ArrayList<Student> arrayList = new ArrayList<>();
            arrayList.add(student);
            arrayList.add(student2);
            arrayList.add(student3);
            // 序列化操作
            // serializ(arrayList);
            
            // 反序列化  
            ObjectInputStream ois  = new ObjectInputStream(new FileInputStream("list.txt"));
            // 读取对象,强转为ArrayList类型
            ArrayList<Student> list  = (ArrayList<Student>)ois.readObject();
            
              for (int i = 0; i < list.size(); i++ ){
                  Student s = list.get(i);
                System.out.println(s.getName()+"--"+ s.getPwd());
              }
        }
    
        private static void serializ(ArrayList<Student> arrayList) throws Exception {
            // 创建 序列化流 
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("list.txt"));
            // 写出对象
            oos.writeObject(arrayList);
            // 释放资源
            oos.close();
        }
    }

    四、打印流

     
    平时我们在控制台打印输出,是调用print方法和println方法完成的,这两个方法都来自于java.io.PrintStream类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式。
     
    • public PrintStream(String fileName): 使用指定的文件名创建一个新的打印流。
    public class PrintDemo {
        public static void main(String[] args) throws IOException {
            // 调用系统的打印流,控制台直接输出97
            System.out.println(97);
          
            // 创建打印流,指定文件的名称
            PrintStream ps = new PrintStream("ps.txt");
              
              // 设置系统的打印流流向,输出到ps.txt
            System.setOut(ps);
              // 调用系统的打印流,ps.txt中输出97
            System.out.println(97);
        }
    }
  • 相关阅读:
    使用pymysql模块进行封装,自动化不可或缺的数据库校验
    使用paramiko模块进行封装,远程操作linux主机
    提高开发效率的 Eclipse 实用操作
    遍历Map的四种方法
    key可以重复的Map集合:IdentityHashMap
    Java根据条件删除Map中元素
    用POI读取具有任意合并单元的excel数据
    【转载】说说JSON和JSONP,也许你会豁然开朗,含jQuery用例
    面向对象的基本原则
    forward和redirect的区别
  • 原文地址:https://www.cnblogs.com/alice-bj/p/12421191.html
Copyright © 2020-2023  润新知