Bootstrap

[Java基础]IO流

字符集

常见字符集

ASCII: 阿斯特码表全称美国信息交换标准代码, 包含英文,数字,符号等

  1. 标准ASCII使用1个字节存储一个字符
  2. 首位是0,因此,总共可表示128个字符,对美国佬来说完全够用

GBK: 汉字内码扩展规范

  1. 汉字编码字符集(国标), 包含2万多个汉字字符
  2. 使用2个字节存储一个中文字符
  3. 兼容ASCLL字符集, 汉字第一个字节的第一位必须是1, 所以可以区分英汉

Unicode字符集: 统一码, 万国码

  1. Unicode是国际组织制定的,可以容纳世界上所有文字、符号的字符集
  2. UTF-32: 4个字节表示一个字符, 可以容纳各国字符, 但是占用空间大, 效率较低, 大家不爱用
  3. UTF-8: 可变长编码方案, 分4个长度区: 1个字节, 2个字节,3个字节,4个字节
  • 英文字符、数字等只占1个字节(兼容标准ASCII编码),汉字字符占用3个字节

  1. 技术人员在开发时都应该使用UTF-8编码
  2. 字符编码时使用的字符集,和解码时使用的字符集必须一致,否则会出现乱码
  3. 英文,数字一般不会乱码,因为很多字符集都兼容了ASCII编码。

小结

  1. ASCII字符集 :只有英文、数字、符号等,占1个字节
  2. GBK字符集:汉字占2个字节,英文、数字占1个字节
  3. UTF-8字符集:汉字占3个字节,英文、数字占1个字节

编码解码

字符编码

字符解码

示例代码

public class Dome1 {
    public static void main(String[] args) throws Exception {
        // 使用程序进行对字符编码解码
        String str = "abc123中国and世界321cba";
        // 1.1UTF-8的编码
        // byte[] bytes = str.getBytes(); // 使用平台的默认字符集进行编码(UTF-8)
        // System.out.println(bytes.length); // 27
        // System.out.println(Arrays.toString(bytes)); // [97, 98, 99, 49, 50, 51, -28, -72, -83, -27, -101, -67, 97, 110, 100, -28, -72, -106, -25, -107, -116, 51, 50, 49, 99, 98, 97]

        // 1.2UTF-8的解码
        // String str1 = new String(bytes);
        // System.out.println(str1); // abc123中国and世界321cba

        // 2.1GBK的编码
        byte[] bytes = str.getBytes("GBK"); // 指定字符集进行编码
        System.out.println(bytes.length); // 23
        System.out.println(Arrays.toString(bytes)); // [97, 98, 99, 49, 50, 51, -42, -48, -71, -6, 97, 110, 100, -54, -64, -67, -25, 51, 50, 49, 99, 98, 97]

        // 2.2GBK的解码
        String str2 = new String(bytes, "GBK");
        System.out.println(str2); // abc123中国and世界321cba
    }
}

IO流

认识IO流

IO流用于读写数据 (读写文件, 或者网络中的数据)

  1. I指Inpot, 称为输入流, 负责把数据读取到内存中
  2. O指Oitput, 称为输出流, 负责写数据到硬盘或网络

应用场景

IO流的分类

  1. 字节输入流 InputStream (读字节数据的)
  2. 字节输出流 OutputStream (写字节数据出去的)
  3. 字符输入流 Reader(读字符数据的)
  4. 字符输出流 Writer(写字符数据出去的)

字节流

字节流: 适合操作所有类型的文件, 特别适合数据的迁移, 如文件复制, 不适合读取文本

1. 字节输入流 FileInputStream

以内存为基准, 把磁盘文件中的数据以字节的形式读取到内存中

示例1: 每次读取一个字节

public class Dome2 {
    public static void main(String[] args) throws Exception {
        // 认识字节输入流, 把文件中的字节数据读取到内存中
        // 1.创建字节输入流对象
        // FileInputStream fis = new FileInputStream(new File("\\day03-io\\src\\com\\ithiema\\doem\\1.text")); // 完整写法
        FileInputStream fis = new FileInputStream("day03-io\\src\\com\\ithiema\\doem\\1.text"); // 简写

        // 2.读取文件中的字节数据
        // 每次读取一个字节
       int b;
       while ((b = fis.read()) != -1) {
           // 每次读取一个字节, 性能较差, 读取汉字输出一定会乱码!
           System.out.print((char) b); // abcd123
       }

        fis.close(); // 关闭管道,释放资源
    }
}

  • 使用read()方法每次读取一个字节, 读取性能差(频繁调用系统), 并且读取汉字会乱码

示例2: 每次读取多个字节

public class Dome2 {
    public static void main(String[] args) throws Exception {
        // 认识字节输入流, 把文件中的字节数据读取到内存中
        // 1.创建字节输入流对象
        // FileInputStream fis = new FileInputStream(new File("\\day03-io\\src\\com\\ithiema\\doem\\1.text")); // 完整写法
        FileInputStream fis = new FileInputStream("day03-io\\src\\com\\ithiema\\doem\\1.text"); // 简写
        
        // 3.每次读取多个字节
        // 性能得到提升: 因为每次读取多个字节,可以减少硬盘和内存的交互次数,从而提升性能。
       byte[] buffer = new byte[3];
       int len;
       while ((len = fis.read(buffer)) != -1) {
           // 把读取到的字节数组转成字符串输出, 读取多少倒出多少
           // 无法避免读取汉字输出乱码的问题: 存在截断汉字字节的可能性!
           String str = new String(buffer, 0, len);
           System.out.print(str); // abcd123
       }

        fis.close(); // 关闭管道,释放资源

    }
}
  • 读取性能会有明显提升, 但是不能避免汉字乱码问题

示例3: 一次读取全部字节

Java官方为InputStream提供了如下方法,可以直接把文件的全部字节读取到一个字节数组中返回

public class Dome2 {
    public static void main(String[] args) throws Exception {
        // 认识字节输入流, 把文件中的字节数据读取到内存中
        // 1.创建字节输入流对象
        // FileInputStream fis = new FileInputStream(new File("\\day03-io\\src\\com\\ithiema\\doem\\1.text")); // 完整写法
        FileInputStream fis = new FileInputStream("day03-io\\src\\com\\ithiema\\doem\\1.text"); // 简写

        // 4.一次读取文件全部字节
        // 避免截断汉字字节的可能性, 输出汉字不会乱码!
        byte[] bytes = fis.readAllBytes();
        String rs = new String(bytes);
        System.out.println(rs); // abcd中国123

        fis.close(); // 关闭管道,释放资源

    }
}
  • 定义与文件一样大小的字节数组, 一次性读取文件的全部字节, 避免汉字乱码
  • 如果文件很大, 可能会引起内存溢出的问题

2. 字节输出流 FileOutputStream

以内存为基础, 把内存中的数据以字节的形式写到文件中

public class Dome3 {
    public static void main(String[] args) throws Exception {
        // 使用字节输出流将字节数据写入到文件中
        // 1.创建字节输出流对象
        // FileOutputStream os = new FileOutputStream("day03-io\\src\\com\\ithiema\\doem\\2.text"); // 覆盖管道
         FileOutputStream os = new FileOutputStream("day03-io\\src\\com\\ithiema\\doem\\2.text", true); // 追加管道

        // 2.写入数据
        os.write('a'); //写入字符数据
        os.write(97);  //写入字节数据
        os.write('国'); //写入字符数据, 汉字会乱码

        // 3.写入字节数组
        os.write("\r\n".getBytes()); //换行符
        byte[] bytes = "我爱你中国666".getBytes();
        os.write(bytes);

        // 4.写入字节数组的一部分
        os.write(bytes, 0, 3); //写入"我", 汉字3个字节

        os.close(); // 关闭流
    }
}

3. 文件复制

任何文件的底层都是字节,字节流做复制就是一字不漏的转移完全部字节,只要复制后、的文件格式一致就没问题! 字节流非常适合做文件的复制操作!

public class Dome4 {
    public static void main(String[] args) {
        // 完成文件的复制
        // 复制文件的时候必须带文件名, 无法自动生成文件名
        try {
            copyFile("day03-io\\src\\com\\ithiema\\doem\\2.text", "day03-io\\src\\com\\ithiema\\doem\\3.text");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 复制文件
     *
     * @param srcPath  源文件路径
     * @param destPath 目录路径
     */
    private static void copyFile(String srcPath, String destPath) throws Exception {
        //1.创建输入流和输出流对象
        FileInputStream fis = new FileInputStream(srcPath);
        FileOutputStream fos = new FileOutputStream(destPath);

        //2.读取文件内容
        byte[] buffer = new byte[1024];
        int len;
        while ((len = fis.read(buffer)) != -1) {
            fos.write(buffer, 0, len); // 读到多少数据, 就写多少数据, 防止残留数据污染文件
        }
        System.out.println("复制成功");

        fos.close();
        fis.close();

    }
}

4. 释放资源

try-catch-finally

public class Dome5 {
    public static void main(String[] args) {
        // 资源释放方案
        copyFile("day03-io\\src\\com\\ithiema\\doem\\2.text", "day03-io\\src\\com\\ithiema\\doem\\3.text");
    }

    /**
     * 复制文件
     *
     * @param srcPath  源文件路径
     * @param destPath 目录路径
     */
    private static void copyFile(String srcPath, String destPath)  {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            // 可能的异常
            int num = 0 / 10;

            //1.创建输入流和输出流对象
            fis = new FileInputStream(srcPath);
            fos = new FileOutputStream(destPath);

            // 可能的异常
            int num2 = 0 / 10;

            //2.读取文件内容
            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, len); // 读到多少数据, 就写多少数据, 防止残留数据污染文件
            }
            System.out.println("复制成功");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 统一释放资源,而且代码出现异常,也能释放资源
            try {
                if(fis != null) fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                if(fos != null) fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
  1. finally代码区: 无论try中的程序是正常还是异常,最后都一定会执行finally区,除非IVM终止。
  2. 作用: 一般用于在程序执行完成后进行资源的释放操作(专业级做法)

try-with-resource

public class Dome6 {
    public static void main(String[] args) {
        // 资源释放方案
        copyFile("day03-io\\src\\com\\ithiema\\doem\\2.text", "day03-io\\src\\com\\ithiema\\doem\\3.text");
    }

    /**
     * 复制文件
     *
     * @param srcPath  源文件路径
     * @param destPath 目录路径
     */
    private static void copyFile(String srcPath, String destPath) {
        try (
                //1.创建输入流和输出流对象
                //这里只能放置资源对象, 用完后,最终会自动关闭资源
                FileInputStream fis = new FileInputStream(srcPath);
                FileOutputStream fos = new FileOutputStream(destPath);
        ) {
            // 可能的异常
            int num = 0 / 10;

            //2.读取文件内容
            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, len); // 读到多少数据, 就写多少数据, 防止残留数据污染文件
            }
            System.out.println("复制成功");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  1. JDK 7开始提供了更简单的资源释放方案
  2. 该资源使用完毕后,会自动调用其close()方法,完成对资源的释放!
  3. try()中只能放置资源,否则报错
  4. 资源一般指的是最终实现了AutoCloseable接口

字符流

字符流: 适合操作纯文本文件 , 不会乱码

字符输入流 FileReader

以内存为基准, 可以把文件中的数据以字符的形式读取到内存中

public class Dome7 {
    public static void main(String[] args) {
        // 掌握字符输入流

        try (
                // 1. 创建字符输入流对象
                FileReader fr = new FileReader("day03-io\\src\\com\\ithiema\\doem\\3.text");
        ) {

            // 2.每次读取多个字符
            char[] chars = new char[3];
            int len;
            while ((len = fr.read(chars)) != -1) {
                // 3.把读取到的字符数组, 转成字符串输出
                // 拓展:文件字符输入流每次读取多个字符,性能较好,
                // 而且读取中文是按照字符读取,不会出现乱码! 这是一种读取中文很好的方案。
                String str = new String(chars, 0, len);
                System.out.print(str);
            }
            System.out.println("读取完毕");
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

字符输出流 FileWriter

以内存为基准, 把内存中的数据以字符的形式写到文件中

public class Dome8 {
    public static void main(String[] args) {
        // 掌握字符输出流
        try (
                // 1. 创建字符输出流对象
                // FileWriter fw = new FileWriter("day03-io\\src\\com\\ithiema\\doem\\4.text"); // 覆盖管道
                FileWriter fw = new FileWriter("day03-io\\src\\com\\ithiema\\doem\\4.text"); // 组加管道
        ) {
            // 2. 写入1个字符
            fw.write("a");
            fw.write(98);
            fw.write("中");

            // 3.写入字符串
            fw.write("\r\n");
            fw.write("中国爱你");

            // 4.写入字符串的一部分
            fw.write("java工资高", 0, 3);

            // 5.写入字符数组
            fw.write("我爱你中国666".toCharArray());

            // 6.写入字符数组的一部分
            char[] chars = "好好学习".toCharArray();
            fw.write(chars, 0, 3);

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

字符输出流写出数据后, 必须刷新流, 或者关闭流, 写出的数据才能生效

  1. java为了提高程序的写出效率, 会把写出的字符先保存到暂存区(内存中), 等刷新或者关闭流的时候, 再调用系统能力把字符写到文件中
  2. 刷新流之后, 流还可以继续使用
  3. 关闭流之后, 流无法使用了
  4. 关闭流包含了刷新流, 及时释放资源很重要

缓冲流

字节缓冲流

字节缓冲流继承字节流

缓冲流可以提高字节流读取和写入数据的性能

  1. 缓冲字节输入流自带了8KB缓冲池
  2. 缓冲字节输出流也自带了8KB缓冲池

创建缓冲流, 然后包装字节流, 字节的读写性能得到提升

public class Dome9 {
    public static void main(String[] args) {
        // 使用字节缓存流复制文
        // 使用上没有变化, 性能提升了
        copyFile("day03-io\\src\\com\\ithiema\\doem\\2.text", "day03-io\\src\\com\\ithiema\\doem\\5.text");
    }

    /**
     * 复制文件
     *
     * @param srcPath  源文件路径
     * @param destPath 目录路径
     */
    private static void copyFile(String srcPath, String destPath) {
        try (
                //1.创建输入流和输出流对象
                FileInputStream fis = new FileInputStream(srcPath);
                FileOutputStream fos = new FileOutputStream(destPath);

                //2.把低级的字节流包装为高级的缓存字节流
                BufferedInputStream bis = new BufferedInputStream(fis);
                BufferedOutputStream bos = new BufferedOutputStream(fos);
        ) {

            //2.读取文件内容
            byte[] buffer = new byte[1024];
            int len;
            while ((len = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, len); // 读到多少数据, 就写多少数据, 防止残留数据污染文件
            }
            System.out.println("复制成功");

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

字符缓冲流

字符缓冲流继承字符流

缓冲流可以提高字节符流读取和写入数据的性能

  1. 缓冲字符输入流自带了8KB缓冲池
  2. 缓冲字符输出流也自带了8KB缓冲池

创建缓冲字符输入流, 缓冲字符输入流提供了按行读取字符的方法

public class Dome10 {
    public static void main(String[] args) {
        // 使用缓冲字符流读取数据
        try (
                // 1. 创建字符输入流对象
                FileReader fr = new FileReader("day03-io\\src\\com\\ithiema\\doem\\4.text");
                // 2. 创建缓冲字符输入流对象
                BufferedReader br = new BufferedReader(fr);
        ) {

            // 3.按行读取数据
            String len;
            while ((len = br.readLine()) != null) {
                // 4. 输出读取的数据
                // 这是目前读取文本最优雅的方案, 性能好, 不乱码, 按行读取不会破坏数据的顺序
                System.out.print(len);         
            }
            System.out.println("读取完毕");

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

创建缓冲字符输出流, 缓冲字符输出流提供了换行方法

public class Dome11 {
    public static void main(String[] args) {
        // 使用缓冲字符流写出数据
        // 掌握字符输出流
        try (
                // 1. 创建字符输出流对象
                FileWriter fw = new FileWriter("day03-io\\src\\com\\ithiema\\doem\\6.text");
                // 2. 创建缓冲字符输出流对象
                BufferedWriter bw = new BufferedWriter(fw);
        ) {
            // 3. 写出1个字符
            bw.write("a");
            bw.write(98);
            bw.write("中");

            // 4.写出字符串
            bw.newLine(); // 换行
            bw.write("中国爱你");

            // 5.写出字符串的一部分
            bw.write("java工资高", 0, 3);

            // 6.写出字符数组
            bw.write("我爱你中国666".toCharArray());

            // 7.写出字符数组的一部分
            char[] chars = "好好学习".toCharArray();
            bw.write(chars, 0, 3);

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

性能分析

分别使用原始的字节流,以及字节缓冲流复制一个很大的视频, 测试性能

public class Dome13 {
    public static final String SRC_FILE = "day03-io\\src\\com\\ithiema\\doem\\8.text";
    public static final String DEST_FILE = "day03-io\\src\\com\\ithiema\\doem\\";

    public static void main(String[] args) {
        // 分析普通字节流和缓冲字节流的性能
        // 1.使用低级的字节流按照一个一个字节的形式复制文件,
        copyFile1(); // 非常慢, 无法忍受, 10min
        // 2.使用低级的字节流按照字节数组的形式复制文件,
        copyFile2(); // 比较慢, 还能接受, 6.399s
        // 3.使用高级的缓冲字节流按照一个一个字节的形式复制文件,
        copyFile3(); // 比较慢, 无法接受, 21.819s
        // 4.使用高级的缓冲字节流按照字节数组的形式复制文件
        copyFile4(); // 非常块, 1.182s
    }

    private static void copyFile4() {
        long start = System.currentTimeMillis();
        try (
                FileInputStream fis = new FileInputStream(SRC_FILE);
                BufferedInputStream bis = new BufferedInputStream(fis);
                FileOutputStream fos = new FileOutputStream(DEST_FILE + "11.text");
                BufferedOutputStream bos = new BufferedOutputStream(fos);
        ) {
            byte[] bytes = new byte[1024];
            int len;
            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) / 1000.0 + "s");
    }

    private static void copyFile3() {
        long start = System.currentTimeMillis();
        try (
                FileInputStream fis = new FileInputStream(SRC_FILE);
                BufferedInputStream bis = new BufferedInputStream(fis);
                FileOutputStream fos = new FileOutputStream(DEST_FILE + "10.text");
                BufferedOutputStream bos = new BufferedOutputStream(fos);
        ) {
            int b;
            while ((b = bis.read()) != -1) {
                bos.write(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("缓冲字节流单个字节复制文件耗时:" + (end - start) / 1000.0 + "s");
    }

    private static void copyFile2() {
        long start = System.currentTimeMillis();
        try (
                FileInputStream fis = new FileInputStream(SRC_FILE);
                FileOutputStream fos = new FileOutputStream(DEST_FILE + "9.text");
        ) {
            byte[] bytes = new byte[1024];
            int len;
            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("普通字节流批量复制文件耗时:" + (end - start) / 1000.0 + "s");
    }

    private static void copyFile1() {
        long start = System.currentTimeMillis();
        try (
                FileInputStream fis = new FileInputStream(SRC_FILE);
                FileOutputStream fos = new FileOutputStream(DEST_FILE + "8.text");
        ) {
            int b;
            while ((b = fis.read()) != -1) {
                fos.write(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();
        System.out.println("普通字节流单个字节复制文件耗时:" + (end - start) / 1000.0 + "s");
    }
}
  1. 建议使用字节缓冲输入流、字节缓冲输出流,结合字节数组的方式目前来看是性能最优的组合。
  2. 特殊情况下,可以通过调整原始流的字节数组, 也能让原始流获得很好的性能
  3. 原始流的字节数组, 越大性能越好, 但是大到一定程度,提升就很小了, 需用通过调试, 找到字节数组的最佳值

其他流

字符输入转换流

继承自字符输入流

InputStreamReader可以解决文件编码不同时,字符流读取文本内容乱码的问题。

  1. 解决思路: 先获取文件的原始字节流,再将其按真实的字符集编码转成字符输入流,这样字符输入流中的字符就不乱码了。

示例代码

public class Dome14 {
    public static void main(String[] args) {
        // 使用字符输入转换流, 读取其他编码格式的文件
        // 不同编码读取文件会乱码:
        // 程序: UTF-8 文件: UTF-8 // 正常读取
        // 程序: UTF-8 文件: GBK // 读取乱码
        try (
                // 1. 创建字符输入流(7.text的编码格式是GBK)
                FileInputStream fis = new FileInputStream("day03-io\\src\\com\\ithiema\\doem\\7.text");
                // 2. 把字符输入流包装成字符转换输入流, 指定目标文件的编码格式
                InputStreamReader isr = new InputStreamReader(fis, "gbk");
                // 3. 把字符转换输入流包装成字符缓冲输入流
                BufferedReader br = new BufferedReader(isr);
        ) {
            // 4. 读取文件内容
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }

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

打印流

打印流分为字节打印流和字符打印流, 继承关系如下

打印流可以实现更方便、更高效的打印数据出去, 能实现打印啥出去就是啥出去

PrintStream提供的打印数据的方案

PrintWriter提供的打印数据的方案

package com.ithiema.doem;

import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;

public class Dome15 {
    public static void main(String[] args) {
        // 了解打印流
        try (
                PrintStream ps = new PrintStream("day03-io\\src\\com\\ithiema\\doem\\7.text"); // 字节打印流
                PrintWriter pw = new PrintWriter("day03-io\\src\\com\\ithiema\\doem\\7.text"); // 字符打印流, 一样用
                PrintStream ps2 = new PrintStream(new FileOutputStream("\"day03-io\\\\src\\\\com\\\\ithiema\\\\doem\\\\7.text\""), true); // 字节打印流,追加管道
        ) {
            // 打印数据, 所见即所得
            ps.print(97);
            ps.print("a");
            ps.println("hello world");
            ps.println(true);
            ps.println(3.14);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  1. 使用输出流写出97, 文件中得到的是a, 因为数字会被转成字符, 打印流可以所见即所得
  2. 打印流一般是指: PrintStream,PrintWriter两个类
  3. 打印功能2者是一样的使用方式
  4. PrintStream继承自字节输出流OutputStream,支持写字节
  5. PrintWrite继承自字符输出流Writer,支持写字符

数据流

作用: 把数据和数据的类型一起进行读写操作

数据输入流

创建数据输入流

输入的方法

数据输出流

创建数据输出流

输出的方法

序列化流

作用: 把Java对象进行序列化/反序列化, 然后读写

对象字节输出流

创建对象

提供方法

注意: 对象如果需要序列化, 必须实现序列化接口 implements Serializable

对象字节输入流

创建对象

读取方法

补充: 如果对象的某些成员不希望参与列序列化, 可以使用transient关键字修饰, 表示不参与序列化

补充: 如果需要序列化多个对象, 可以用法ArrayList集合存放对象, 然后操作集合即可,

ArrayList集合已经实现了序列化接口

包装流

输入输出流

字符缓冲输入流

作用: 自带8kb的缓冲池, 提高读取性能

字符缓冲输出流

特殊数据流

继承关系

DataOutputStream(数据输出流), 允许把数据和其类型一并写出去。

public class Dome17 {
    public static void main(String[] args) {
        // 了解特殊数据输出流
        try (
                DataOutputStream dos = new DataOutputStream(new FileOutputStream("day03-io\\src\\com\\ithiema\\doem\\7.text"));
        ) {
            dos.writeByte(34);
            dos.writeUTF("hello");
            dos.writeInt(100);
            dos.writeDouble(3.14);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  1. 写出的数据是这种格式, 并不是乱码, 因为包含了数据类型, 所以看起来不直观

DatalnputStream(数据输入流), 用于读取数据输出流写出去的数据。

public class Dome16 {
    public static void main(String[] args) {
        // 了解特殊数据输入流
        try (
                DataInputStream dis = new DataInputStream(new FileInputStream("day03-io\\src\\com\\ithiema\\doem\\7.text"));
        ) {
            System.out.println(dis.readByte());
            System.out.println(dis.readUTF());
            System.out.println(dis.readInt());
            System.out.println(dis.readDouble());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

IO框架

框架(Framework)是一个预先写好的代码库或一组工具,旨在简化和加速开发过程

  1. 框架的形式: 一般是把类、接口等编译成class形式,再压缩成一个.jar结尾的文件发行出去。

Commons-io: 阿帕奇开源基金组织提供的一套有关IO操作的框架

  1. 进一步封装了Java的IO流操作,对外提供了更简单的方式来对文件进行操作,对数据进行读写等。
  2. 下载框架: Commons IO – Download Apache Commons IO

  1. 在项目中新建lib文件夹, 将commons-io-2.6.jar文件复制进去

  1. 在jar文件上点右键,选择 Add as Library->点击oK, 把框架集成到项目

使用Commons-io提供的方法, 简化IO流的代码

public class Dome18 {
    public static void main(String[] args) throws IOException {
        // 使用Commons-io框架
        // 1.复制文件
        FileUtils.copyFile(new File("day03-io\\src\\com\\ithiema\\doem\\8.text"), new File("day03-io\\src\\com\\ithiema\\doem\\9.text"));

        // 2.读取数据
        String str = FileUtils.readFileToString(new File("day03-io\\src\\com\\ithiema\\doem\\9.text"), "UTF-8");
        System.out.println(str);
    }
}
;