JavaSE基础笔记——IO流2:缓冲流;转换流;序列化与反序列化对象;打印流;补充知识:Properties、IO框架

1、缓冲流

缓冲流概述

  • 缓冲流也称为高效流、或者高级流。之前学习的字节流可以称为原始流。
  • 缓冲流作用:缓冲流自带缓冲区、可以提高原始字节流、字符流读写数据的性能。 

缓冲流分类:

字节缓冲流性能优化原理:

  • 字节缓冲输入流自带了8KB缓冲池,以后我们直接从缓冲池读取数据,所以性能较好。
  • 字节缓冲输出流自带了8KB缓冲池,数据就直接写入到缓冲池中去,写数据性能极高了。

字节缓冲流为什么提高了操作数据的性能?

字节缓冲流自带8KB缓冲区 可以提高原始字节流、字符流读写数据的性能。

字节缓冲流:

  1. 字节缓冲输入流:BufferedInputStream,提高字节输入流读取数据的性能。  
  2. 字节缓冲输出流:BufferedOutputStream,提高字节输出流读取数据的性能。

构造器

说明

public BufferedInputStream​(InputStream is)

可以把低级的字节输入流包装成一个高级的缓冲字节输入流管道,从而提高字节输入流读数据的性能

public BufferedOutputStream​(OutputStream os)

可以把低级的字节输出流包装成一个高级的缓冲字节输出流,从而提高写数据的性能

/**
    目标:使用字节缓冲流完成数据的读写操作。
 */
public class ByteBufferDemo {
    public static void main(String[] args) {
        try (
                // 这里面只能放置资源对象,用完会自动关闭:自动调用资源对象的close方法关闭资源(即使出现异常也会做关闭操作)
                // 1、创建一个字节输入流管道与原视频接通
                InputStream is = new FileInputStream("D:\\resources\\newmeinv.jpeg");
                // a.把原始的字节输入流包装成高级的缓冲字节输入流
                InputStream bis = new BufferedInputStream(is);
                // 2、创建一个字节输出流管道与目标文件接通
                OutputStream os = new FileOutputStream("D:\\resources\\newmeinv222.jpeg");
                // b.把字节输出流管道包装成高级的缓冲字节输出流管道
                OutputStream bos = new BufferedOutputStream(os);
        ) {
            // 3、定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len; // 记录每次读取的字节数。
            while ((len = bis.read(buffer)) != -1){
                bos.write(buffer, 0 , len);
            }
            System.out.println("复制完成了!");

        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

 字节缓冲流的性能分析

1、我们已经说明了字节缓冲流的性能高效,但是没有直接感受到。

2、如何测试字节缓冲流的读写性能呢?

目标:利用字节流的复制统计各种写法形式下缓冲流的性能执行情况。

需求:

分别使用低级字节流和高级字节缓冲流拷贝大视频,记录耗时。

分析:
(1)使用低级的字节流按照一个一个字节的形式复制文件。
(2)使用低级的字节流按照一个一个字节数组的形式复制文件。
(3)使用高级的缓冲字节流按照一个一个字节的形式复制文件。
(4)使用高级的缓冲字节流按照一个一个字节数组的形式复制文件。

源文件:视频
目标文件:文件夹

public class ByteBufferTimeDemo {
    private static final String SRC_FILE = "D:\\Java\\2022最新版Java学习路线图\\第1阶段—Java基础\\1、Java基础-20天学会Java\\最新JavaSE基础加强课程14天\\day10、IO流二\\视频\\01、今日课程安排.avi";
    private static final String DEST_FILE = "D:\\Java\\";

    public static void main(String[] args) {
        //copy01(); // 使用低级的字节流按照一个一个字节的形式复制文件:慢的让人简直无法忍受。直接被淘汰。
        copy02(); // 使用低级的字节流按照一个一个字节数组的形式复制文件: 比较慢,但是还是可以忍受的!
        copy03(); // 缓冲流一个一个字节复制:很慢,不建议使用。
        copy04(); // 缓冲流一个一个字节数组复制:飞快,简直太完美了(推荐使用)
    }

    private static void copy04() {
        long startTime = System.currentTimeMillis();
        try (
                // 1、创建低级的字节输入流与源文件接通
                InputStream is = new FileInputStream(SRC_FILE);
                // a.把原始的字节输入流包装成高级的缓冲字节输入流
                InputStream bis = new BufferedInputStream(is);
                // 2、创建低级的字节输出流与目标文件接通
                OutputStream os = new FileOutputStream(DEST_FILE + "video4.avi");
                // b.把字节输出流管道包装成高级的缓冲字节输出流管道
                OutputStream bos = new BufferedOutputStream(os);
        ) {

            // 3、定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len; // 记录每次读取的字节数。
            while ((len = bis.read(buffer)) != -1){
                bos.write(buffer, 0 , len);
            }

        } catch (Exception e){
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("使用缓冲的字节流按照一个一个字节数组的形式复制文件耗时:" + (endTime - startTime)/1000.0 + "s");
    }



    private static void copy03() {
        long startTime = System.currentTimeMillis();
        try (
                // 1、创建低级的字节输入流与源文件接通
                InputStream is = new FileInputStream(SRC_FILE);
                // a.把原始的字节输入流包装成高级的缓冲字节输入流
                InputStream bis = new BufferedInputStream(is);
                // 2、创建低级的字节输出流与目标文件接通
                OutputStream os = new FileOutputStream(DEST_FILE + "video3.avi");
                // b.把字节输出流管道包装成高级的缓冲字节输出流管道
                OutputStream bos = new BufferedOutputStream(os);
        ){

            // 3、定义一个变量记录每次读取的字节(一个一个字节的复制)
            int b;
            while ((b = bis.read()) != -1){
                bos.write(b);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("使用缓冲的字节流按照一个一个字节的形式复制文件耗时:" + (endTime - startTime)/1000.0 + "s");
    }


    private static void copy02() {
        long startTime = System.currentTimeMillis();
        try (
                // 这里面只能放置资源对象,用完会自动关闭:自动调用资源对象的close方法关闭资源(即使出现异常也会做关闭操作)
                // 1、创建一个字节输入流管道与原视频接通
                InputStream is = new FileInputStream(SRC_FILE);
                // 2、创建一个字节输出流管道与目标文件接通
                OutputStream os = new FileOutputStream(DEST_FILE + "video2.avi")
        ) {

            // 3、定义一个字节数组转移数据
            byte[] buffer = new byte[1024];
            int len; // 记录每次读取的字节数。
            while ((len = is.read(buffer)) != -1){
                os.write(buffer, 0 , len);
            }
        } catch (Exception e){
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("使用低级的字节流按照一个一个字节数组的形式复制文件耗时:" + (endTime - startTime)/1000.0 + "s");
    }

    /**
      使用低级的字节流按照一个一个字节的形式复制文件
     */
    private static void copy01() {
        long startTime = System.currentTimeMillis();
        try (
                // 1、创建低级的字节输入流与源文件接通
                InputStream is = new FileInputStream(SRC_FILE);
                // 2、创建低级的字节输出流与目标文件接通
                OutputStream os = new FileOutputStream(DEST_FILE + "video1.avi")
                ){

            // 3、定义一个变量记录每次读取的字节(一个一个字节的复制)
            int b;
            while ((b = is.read()) != -1){
                os.write(b);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("使用低级的字节流按照一个一个字节的形式复制文件耗时:" + (endTime - startTime)/1000.0 + "s");
    }

}

推荐使用哪种方式提高字节流读写数据的性能?

建议使用字节缓冲输入流、字节缓冲输出流,结合字节数组的方式,目前来看是性能最优的组合。

 字符缓冲流

字符缓冲输入流:BufferedReader。

作用:提高字符输入流读取数据的性能,除此之外多了按照行读取数据的功能。

构造器

说明

public BufferedReader​(Reader r)

可以把低级的字符输入流包装成一个高级的缓冲字符输入流管道,从而提高字符输入流读数据的性能

字符缓冲输出流新增功能

方法

说明

public void newLine()

换行操作

/**
    目标:学会使用缓冲字符输入流提高字符输入流的性能,新增了按照行读取的方法(经典代码)
 */
public class BufferedReaderDemo1 {
    public static void main(String[] args) {
        try (
                // 1、创建一个文件字符输入流与源文件接通。
                Reader fr = new FileReader("io-app2/src/data01.txt");
                // a、把低级的字符输入流包装成高级的缓冲字符输入流。
                BufferedReader br = new BufferedReader(fr);
                ){

            // 2、用循环,每次读取一个字符数组的数据。  1024 + 1024 + 8
//            char[] buffer = new char[1024]; // 1K字符
//            int len;
//            while ((len = br.read(buffer)) != -1) {
//                String rs = new String(buffer, 0, len);
//                System.out.print(rs);
//            }

              String line;
              while ((line = br.readLine()) != null){
                  System.out.println(line);
              }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

字符缓冲输出流:BufferedWriter。  

作用:提高字符输出流写取数据的性能,除此之外多了换行功能。

构造器

说明

public BufferedWriter​(Writer w)

可以把低级的字符输出流包装成一个高级的缓冲字符输出流管道,从而提高字符输出流写数据的性能

字符缓冲输出流新增功能

方法

说明

public void newLine()

换行操作

/**
     目标:缓冲字符输出流的使用,学会它多出来的一个功能:newLine();
 */
public class BufferedWriterDemo2 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个字符输出流管道与目标文件接通
        Writer fw = new FileWriter("io-app2/src/out02.txt"); // 覆盖管道,每次启动都会清空文件之前的数据
       //Writer fw = new FileWriter("io-app2/src/out02.txt", true); // 追加数据
        BufferedWriter bw = new BufferedWriter(fw);

//      a.public void write(int c):写一个字符出去
        bw.write(98);
        bw.write('a');
        bw.write('徐'); // 不会出问题了
        bw.newLine(); // bw.write("\r\n"); // 换行

//       b.public void write(String c)写一个字符串出去
        bw.write("abc我是中国人");
        bw.newLine(); // bw.write("\r\n"); // 换行
        
//       c.public void write(char[] buffer):写一个字符数组出去
        char[] chars = "abc我是中国人".toCharArray();
        bw.write(chars);
        bw.newLine(); // bw.write("\r\n"); // 换行
        
//       d.public void write(String c ,int pos ,int len):写字符串的一部分出去
        bw.write("abc我是中国人", 0, 5);
        bw.newLine(); // bw.write("\r\n"); // 换行

//       e.public void write(char[] buffer ,int pos ,int len):写字符数组的一部分出去
        bw.write(chars, 3, 5);
        bw.newLine(); // bw.write("\r\n"); // 换行
        
        // fw.flush();// 刷新后流可以继续使用
        bw.close(); // 关闭包含刷线,关闭后流不能使用
    }
}

字符缓冲流为什么提高了操作数据的性能?

  • 字符缓冲流自带8K缓冲区
  • 可以提高原始字符流读写数据的性能

字符缓冲流的功能如何使用?

  • public BufferedReader​(Reader r)
  • 性能提升了,多了readLine()按照行读取的功能
  • public BufferedWriter​(Writer w)
  • 性能提升了,多了newLine()换行的功能

案例:拷贝出师表到另一个文件,恢复顺序

需求:把《出师表》的文章顺序进行恢复到一个新文件里 

分析:

  1. 定义一个缓存字符输入流管道与源文件接通。
  2. 定义一个List集合存储读取的每行数据。
  3. 定义一个循环按照行读取数据,存入到List集合中去。
  4. 对List集合中的每行数据按照首字符编号升序排序。
  5. 定义一个缓存字符输出管道与目标文件接通。
  6. 遍历List集合中的每个元素,用缓冲输出管道写出并换行。
/**
   目标:完成出师表顺序的恢复,并存入到另一个新文件中去。
 */
public class BufferedCharTest3 {
    public static void main(String[] args) {
        try(
                // 1、创建缓冲字符输入流管道与源文件接通
                BufferedReader br = new BufferedReader(new FileReader("D:\\Java\\2022最新版Java学习路线图\\第1阶段—Java基础\\1、Java基础-20天学会Java\\最新JavaSE基础加强课程14天\\day10、IO流二\\代码\\io-app2\\src\\csb.txt"));

                // 5、定义缓冲字符输出管道与目标文件接通
                BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\Java\\2022最新版Java学习路线图\\第1阶段—Java基础\\1、Java基础-20天学会Java\\最新JavaSE基础加强课程14天\\day10、IO流二\\代码\\io-app2\\src\\new.txt"));
                ) {

            // 2、定义一个List集合存储每行内容
            List<String> data = new ArrayList<>();
            // 3、定义循环,按照行读取文章
            String line;
            while ((line = br.readLine()) != null){
                data.add(line);
            }
            System.out.println(data);

            // 4、排序
            // 自定义排序规则
            List<String> sizes = new ArrayList<>();
            Collections.addAll(sizes, "一","二","三","四","五","陆","柒","八","九","十","十一");

            Collections.sort(data, new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    // o1   八.,....
                    // o2   柒.,....
                    return sizes.indexOf(o1.substring(0, o1.indexOf(".")))
                            - sizes.indexOf(o2.substring(0, o2.indexOf(".")));
                }
            });
            System.out.println(data);

            // 6、遍历集合中的每行文章写出去,且要换行
            for (String datum : data) {
                bw.write(datum);
                bw.newLine(); // 换行
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2、转换流

1、之前我们使用字符流读取中文是否有乱码?

  • 没有的,因为代码编码和文件编码都是UTF-8。

2、如果代码编码和文件编码不一致,使用字符流直接读取还能不乱码吗?

  • 会乱码。
  • 文件编码和读取的编码必须一致才不会乱码。

需求:

  • 分别使用如下两种方式读取文件内容 代码编码是UTF-8,文件编码也是UTF-8,使用字符流读取观察输出的中文字符结果。
  • 代码编码是UTF-8,文件编码使用GBK,使用字符流读取观察输出的中文字符结果。

字符输入转换流:InputStreamReader

作用:可以解决字符流读取不同编码乱码的问题。可以把原始的字节流按照指定编码转换成字符输入流。

1、如果代码编码和文件编码不一致,使用字符流直接读取还能不乱码吗?

会乱码。

2、如果如何解决呢?

  • 使用字符输入转换流
  • 可以提取文件(GBK)的原始字节流,原始字节不会存在问题。
  • 然后把字节流以指定编码转换成字符输入流,这样字符输入流中的字符就不乱码了。

构造器

说明

public InputStreamReader(InputStream is)

可以把原始的字节流按照代码默认编码转换成字符输入流。几乎不用,与默认的FileReader一样。

public InputStreamReader(InputStream is ,String charset)

可以把原始的字节流按照指定编码转换成字符输入流,这样字符流中的字符就不乱码了(重点)

public class InputStreamReaderDemo01 {
    public static void main(String[] args) throws Exception {
        // 代码UTF-8   文件 GBK  "D:\\resources\\data.txt"
        // 1、提取GBK文件的原始字节流。   abc 我
        //                            ooo oo
        InputStream is = new FileInputStream("D:\\resources\\data.txt");
        // 2、把原始字节流转换成字符输入流
        // Reader isr = new InputStreamReader(is); // 默认以UTF-8的方式转换成字符流。 还是会乱码的  跟直接使用FileReader是一样的
        Reader isr = new InputStreamReader(is , "GBK"); // 以指定的GBK编码转换成字符输入流  完美的解决了乱码问题
        BufferedReader br = new BufferedReader(isr);
        String line;
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }
    }
}

总结

字符输入转换流InputStreamReader作用:

可以解决字符流读取不同编码乱码的问题

public InputStreamReader(InputStream is,String charset):可以指定编码把原始字节流转换成字符流,如此字符流中的字符不乱码。

字符输出转换流:OutputStreamWriter

作用:可以把字节输出流按照指定编码转换成字符输出流。

1、如果需要控制写出去的字符使用的编码,怎么办?

可以把字符以指定编码获取字节后再使用字节输出流写出去:

“我爱你中国”.getBytes(编码) 也可以使用字符输出转换流实现。

构造器

说明

public OutputStreamWriter(OutputStream os)

可以把原始的字节输出流按照代码默认编码转换成字符输出流。几乎不用。

public OutputStreamWriter(OutputStream os,String charset)

可以把原始的字节输出流按照指定编码转换成字符输出流(重点)

public class OutputStreamWriterDemo02 {
    public static void main(String[] args) throws Exception {
        // 1、定义一个字节输出流
        OutputStream os = new FileOutputStream("io-app2/src/out03.txt");

        // 2、把原始的字节输出流转换成字符输出流
        // Writer osw = new OutputStreamWriter(os); // 以默认的UTF-8写字符出去 跟直接写FileWriter一样
        Writer osw = new OutputStreamWriter(os , "GBK"); // 指定GBK的方式写字符出去

        // 3、把低级的字符输出流包装成高级的缓冲字符输出流。
        BufferedWriter bw = new BufferedWriter(osw);
        bw.write("我爱中国1~~");
        bw.write("我爱中国2~~");
        bw.write("我爱中国3~~");
        bw.close();
    }
}

字符输出转换流OutputStreamWriter的作用?

public OutputStreamWriter(OutputStream os,String charset)

可以指定编码把字节输出流转换成字符输出流,从而可以指定写出去的字符编码!

3、序列化与反序列化对象

注意:

在序列化和反向序列化的概念中,是没有文件的。

另外,对象的反序列化是Java中的第二种产生对象的方法。

 

对象序列化:ObjectOutputStream

  • 作用:以内存为基准,把内存中的对象存储到磁盘文件中去,称为对象序列化。
  • 使用到的流是对象字节输出流:ObjectOutputStream

构造器

说明

public ObjectOutputStream(OutputStream out)

把低级字节输出流包装成高级的对象字节输出流

ObjectOutputStream序列化方法

方法名称

说明

public final void writeObject(Object obj)

把对象写出去到对象序列化流的文件中去

学生类:
/**
  对象如果要序列化,必须实现Serializable序列化接口。
 */
public class Student implements Serializable {
    // 申明序列化的版本号码
    // 序列化的版本号与反序列化的版本号必须一致才不会出错!
    private static final long serialVersionUID = 1;
    private String name;
    private String loginName;
    // transient修饰的成员变量不参与序列化了
    private transient String passWord;
    private int age ;

    public Student(){
    }

    public Student(String name, String loginName, String passWord, int age) {
        this.name = name;
        this.loginName = loginName;
        this.passWord = passWord;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", loginName='" + loginName + '\'' +
                ", passWord='" + passWord + '\'' +
                ", age=" + age +
                '}';
    }
}
public class ObjectOutputStreamDemo1 {
    public static void main(String[] args) throws Exception {
        // 1、创建学生对象
        Student s = new Student("陈磊", "chenlei","1314520", 21);

        // 2、对象序列化:使用对象字节输出流包装字节输出流管道
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("io-app2/src/obj.txt"));

        // 3、直接调用序列化方法
        oos.writeObject(s);

        // 4、释放资源
        oos.close();
        System.out.println("序列化完成了~~");
    }
}

Serializable接口是一个没有任何方法的接口,这类接口被称为“标识接口”;

对象必须实现序列化接口Serializable。

它的出现提供接口的第二种用法。
第一种用法:接口是在没有继承关系的类之间提供共享的行为
第二种用法:接口就像是一个标记(章),如果我们允许某个类去做某个操作,我们就让它实现这个接口,否则不具备这个接口的类就不能做这个操作。————就像盖章一样。
对象序列化和反序列化就是这样的一个必须盖章的操作,参与的对象如果没有盖这个章,就不好意思就不允许做序列化或反序列化的操作。而且不仅仅是这个类要实现Serializable接口,该类的所有属性或属性的属性,只要想参与序列化,都必须实现Serializable接口。

属性不进行序列化:使用transient关键字(可选修饰符)

用于在序列化的时候指定某个属性不参与序列化那么序列化出去的二进制数据流当中这个属性的值是null的。如:private transient String username;//用户名

对象反序列化:ObjectInputStream

  • 作用:以内存为基准,把存储到磁盘文件中去的对象数据恢复成内存中的对象,称为对象反序列化。
  • 使用到的流是对象字节输入流:ObjectInputStream。

构造器

说明

public ObjectInputStream(InputStream out)

把低级字节输如流包装成高级的对象字节输入流

ObjectInputStream序列化方法

方法名称

说明

public Object readObject()

把存储到磁盘文件中去的对象数据恢复成内存中的对象返回

/**
    目标:学会进行对象反序列化:使用对象字节输入流把文件中的对象数据恢复成内存中的Java对象。
 */
public class ObjectInputStreamDemo2 {
    public static void main(String[] args) throws Exception {
        // 1、创建对象字节输入流管道包装低级的字节输入流管道
        ObjectInputStream is = new ObjectInputStream(new FileInputStream("io-app2/src/obj.txt"));

        // 2、调用对象字节输入流的反序列化方法
        Student s = (Student) is.readObject();

        System.out.println(s);
    }
}

申明序列化的版本号码

序列化的版本号与反序列化的版本号必须一致才不会出错!
private static final long serialVersionUID = 1;

4、打印流

打印流作用:

  • 打印流可以实现方便、高效的打印数据到文件中去。打印流一般是指:PrintStream,PrintWriter两个类。
  • 可以实现打印什么数据就是什么数据,例如打印整数97写出去就是97,打印boolean的true,写出去就是true。

PrintStream

构造器

说明

public PrintStream(OutputStream os)

打印流直接通向字节输出流管道

public PrintStream(File  f)

打印流直接通向文件对象

public PrintStream(String filepath)

打印流直接通向文件路径

方法

说明

public void print(Xxx xx)

打印任意类型的数据出去

PrintWriter

构造器

说明

public PrintWriter(OutputStream os)

打印流直接通向字节输出流管道

public PrintWriter (Writer w)

打印流直接通向字符输出流管道

public PrintWriter (File  f)

打印流直接通向文件对象

public PrintWriter (String filepath)

打印流直接通向文件路径

方法

说明

public void print(Xxx xx)

打印任意类型的数据出去

/**
    目标:学会使用打印流 高效  方便写数据到文件。
 */
public class PrintDemo1 {
    public static void main(String[] args) throws Exception {
        // 1、创建一个打印流对象
//        PrintStream ps = new PrintStream(new FileOutputStream("io-app2/src/ps.txt"));
//        PrintStream ps = new PrintStream(new FileOutputStream("io-app2/src/ps.txt" , true)); // 追加数据,在低级管道后面加True
//        PrintStream ps = new PrintStream("io-app2/src/ps.txt" );
        PrintWriter ps = new PrintWriter("io-app2/src/ps.txt"); // 打印功能上与PrintStream的使用没有区别

        ps.println(97);
        ps.println('a');
        ps.println(23.3);
        ps.println(true);
        ps.println("我是打印流输出的,我是啥就打印啥");

        ps.close();
    }
}

PrintStream和PrintWriter的区别

  • 打印数据功能上是一模一样的,都是使用方便,性能高效(核心优势)。
  • PrintStream继承自字节输出流OutputStream,支持写字节数据的方法。
  • PrintWriter继承自字符输出流Writer,支持写字符数据出去。

1、打印流有几种?各有什么特点?

  • 打印流一般是指:PrintStream,PrintWriter两个类。
  • 打印功能2者是一样的使用方式
  • PrintStream继承自字节输出流OutputStream,支持写字节
  • PrintWrite继承自字符输出流Writer,支持写字符

2、打印流的优势是什么?

  • 两者在打印功能上都是使用方便,性能高效(核心优势)

 输出语句重定向

  • 属于打印流的一种应用,可以把输出语句的打印位置改到文件。

PrintStream ps = new PrintStream("文件地址")

System.setOut(ps);

public static void main(String[] args) throws Exception {
        System.out.println("锦瑟无端五十弦");
        System.out.println("一弦一柱思华年");

        // 改变输出语句的位置(重定向)
        PrintStream ps = new PrintStream("D:\\Java\\2022最新版Java学习路线图\\第1阶段—Java基础\\1、Java基础-20天学会Java\\最新JavaSE基础加强课程14天\\day10、IO流二\\代码\\io-app2\\src\\log.txt");
        System.setOut(ps); // 把系统打印流改成我们自己的打印流

        System.out.println("庄生晓梦迷蝴蝶");
        System.out.println("望帝春心托杜鹃");
    }

5、补充知识:Properties属性文件类

属性文件类————Properties

.properties
1、属性文件的格式:
文件名通常后缀都是*****.properties,但不是强制要求。
属性文件的内容是以“键-值”对(又叫kv对)的形式存放数据的,其中键不能重复,且键和值都是字符串。比如:key —— value
        zhang3 = 123456
        li4 = 123456
        wang5 = 123456
        用户名 = 密码-余额
2、要操作这种格式的文件,在Java当中需要用到这个Properties类。
Properties类有两个特点:
2-1、它是一个集合类;
2-2、它可以把自己装的元素自动存入到一篇Properties文件里去;也可以从一篇Properties文件里读出数据装在自己本身身上。

Properties属性集对象

properties其实就是一个Map集合,但是我们一般不会当集合使用,因为HashMap更好用。

properties核心作用:

  • Properties代表的是一个属性文件,可以把自己对象中的键值对信息存入到一个属性文件中去。
  • 属性文件:后缀是.properties结尾的文件,里面的内容都是 key=value,后续做系统配置信息的。

Properties的API:

Properties和IO流结合的方法:

构造器

说明

void load​(InputStream inStream)

从输入字节流读取属性列表(键和元素对)

void load​(Reader reader)

从输入字符流读取属性列表(键和元素对)

void store​(OutputStream out, String comments)

将此属性列表(键和元素对)写入此 Properties表中,以适合于使用 load(InputStream)方法的格式写入输出字节流

void store​(Writer writer, String comments)

将此属性列表(键和元素对)写入此 Properties表中,以适合使用 load(Reader)方法的格式写入输出字符流

public Object setProperty(String key, String value) 

保存键值对(put)

public String getProperty(String key) 

使用此属性列表中指定的键搜索属性值 (get)

public Set<String> stringPropertyNames()

所有键的名称的集合  (keySet())

/**
小结:
Properties可以保存键值对数据到属性文件
 */
public class PropertiesDemo01 {
    public static void main(String[] args) throws Exception {
        // 需求:使用Properties把键值对信息存入到属性文件中去。
        Properties properties = new Properties();
        //properties.put("admin","123456");
        properties.setProperty("admin", "123456");//setProperty底层就是put
        properties.setProperty("dlei", "003197");
        properties.setProperty("heima", "itcast");
        System.out.println(properties);

        /**
           参数一:保存管道 字符输出流管道
           参数二:保存心得,这个参数comments可以写null
         */
        properties.store(new FileWriter("io-app2/src/users.properties")
                , "this is users!! i am very happy!");
    }
}
public class PropertiesDemo02 {
    public static void main(String[] args) throws Exception {
        // 需求:Properties读取属性文件中的键值对信息。(读取)
        Properties properties = new Properties();
        System.out.println(properties);

        // 加载属性文件中的键值对数据到属性对象properties中去
        properties.load(new FileReader("io-app2/src/users.properties"));

        System.out.println(properties);
        String rs = properties.getProperty("dlei");
        System.out.println(rs);
        String rs1 = properties.getProperty("admin");
        System.out.println(rs1);
    }
}

Properties的作用?

  • 可以存储Properties属性集的键值对数据到属性文件中去: void store​(Writer writer, String comments)
  • 可以加载属性文件中的数据到Properties对象中来: void load​(Reader reader)

6、补充知识:IO框架

commons-io概述

  • commons-io是apache开源基金组织提供的一组有关IO操作的类库,可以提高IO功能开发的效率。
  • commons-io工具包提供了很多有关io操作的类。有两个主要的类FileUtils, IOUtils。

FileUtils主要方法:

方法名

说明

String readFileToString(File file, String encoding)

读取文件中的数据, 返回字符串

void copyFile(File srcFile, File destFile)

复制文件。

void copyDirectoryToDirectory(File srcDir, File destDir)

复制文件夹。

/**
    目标:Commons-io包的使用介绍。

    什么是Commons-io包?
            commons-io是apache开源基金组织提供的一组有关IO操作的类库,
            可以挺提高IO功能开发的效率。commons-io工具包提供了很多有关io操作的类,

    见下表:
         | 包                                  | 功能描述                                     |
         | ----------------------------------- | :------------------------------------------- |
         | org.apache.commons.io               | 有关Streams、Readers、Writers、Files的工具类 |
         | org.apache.commons.io.input         | 输入流相关的实现类,包含Reader和InputStream  |
         | org.apache.commons.io.output        | 输出流相关的实现类,包含Writer和OutputStream |
         | org.apache.commons.io.serialization | 序列化相关的类

    步骤:
         1. 下载commons-io相关jar包;http://commons.apache.org/proper/commons-io/
         2. 把commons-io-2.6.jar包复制到指定的Module的lib目录中
         3. 将commons-io-2.6.jar加入到classpath中

    小结:
         IOUtils和FileUtils可以方便的复制文件和文件夹!!
 */
public class CommonsIODemo01 {
    public static void main(String[] args) throws Exception {

        // 1.完成文件复制!
//        IOUtils.copy(new FileInputStream("D:\\resources\\hushui.jpeg"),
//                new FileOutputStream("D:\\resources\\hushui2.jpeg"));


        // 2.完成文件复制到某个文件夹下!
//        FileUtils.copyFileToDirectory(new File("D:\\resources\\hushui.jpeg"), new File("D:/"));


          // 3.完成文件夹复制到某个文件夹下!
//          FileUtils.copyDirectoryToDirectory(new File("D:\\resources") , new File("D:\\new"));
//           FileUtils.deleteDirectory(new File("D:\\new"));

         // JDK1.7 自己也做了一些一行代码完成复制的操作:New IO的技术
         // Files.copy(Path.of("D:\\resources\\hushui.jpeg"), Path.of("D:\\resources\\hushui3.jpeg"));

        FileUtils.deleteDirectory(new File("D:\\new"));
    }
}

导入commons-io-2.6.jar做开发

需求:

使用commons-io简化io流读写

分析:

  • 在项目中创建一个文件夹:lib
  • 将commons-io-2.6.jar文件复制到lib文件夹
  • 在jar文件上点右键,选择 Add as Library -> 点击OK
  • 在类中导包使用

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值