• Java文件操作


    一,文件IO

    package cn.itcast_01;
     
    import java.io.File;
     
    /*
    * 我们要想实现IO的操作,就必须知道硬盘上文件的表现形式。
    * 而Java就提供了一个类File供我们使用。
    *
    * File:文件和目录(文件夹)路径名的抽象表示形式
    * 构造方法:
    * File(String pathname):根据一个路径得到File对象
    * File(String parent, String child):根据一个目录和一个子文件/目录得到File对象
    * File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象
    */
    public class FileDemo {
    public static void main(String[] args) {
    // File(String pathname):根据一个路径得到File对象
    // 把e:\demo\a.txt封装成一个File对象
    File file = new File("E:\demo\a.txt");
     
    // File(String parent, String child):根据一个目录和一个子文件/目录得到File对象
    File file2 = new File("E:\demo", "a.txt");
     
    // File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象
    File file3 = new File("e:\demo");
    File file4 = new File(file3, "a.txt");
     
    // 以上三种方式其实效果一样
    }
    }
    ===========================================================
    package cn.itcast_02;
     
    import java.io.File;
    import java.io.IOException;
     
    /*
    *创建功能:
    *public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了
    *public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了
    *public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来
    *
    *骑白马的不一定是王子,可能是班长。
    *注意:你到底要创建文件还是文件夹,你最清楚,方法不要调错了。
    */
    public class FileDemo {
    public static void main(String[] args) throws IOException {
    // 需求:我要在e盘目录下创建一个文件夹demo
    File file = new File("e:\demo");
    System.out.println("mkdir:" + file.mkdir());
     
    // 需求:我要在e盘目录demo下创建一个文件a.txt
    File file2 = new File("e:\demo\a.txt");
    System.out.println("createNewFile:" + file2.createNewFile());
     
    // 需求:我要在e盘目录test下创建一个文件b.txt
    // Exception in thread "main" java.io.IOException: 系统找不到指定的路径。
    // 注意:要想在某个目录下创建内容,该目录首先必须存在。
    // File file3 = new File("e:\test\b.txt");
    // System.out.println("createNewFile:" + file3.createNewFile());
     
    // 需求:我要在e盘目录test下创建aaa目录
    // File file4 = new File("e:\test\aaa");
    // System.out.println("mkdir:" + file4.mkdir());
     
    // File file5 = new File("e:\test");
    // File file6 = new File("e:\test\aaa");
    // System.out.println("mkdir:" + file5.mkdir());
    // System.out.println("mkdir:" + file6.mkdir());
     
    // 其实我们有更简单的方法
    File file7 = new File("e:\aaa\bbb\ccc\ddd");
    System.out.println("mkdirs:" + file7.mkdirs());
     
    // 看下面的这个东西:
    File file8 = new File("e:\liuyi\a.txt");
    System.out.println("mkdirs:" + file8.mkdirs());
    }
    }
    ============================================================
    package cn.itcast_03;
     
    import java.io.File;
    import java.io.IOException;
     
    /*
    * 删除功能:public boolean delete()
    *
    * 注意:
    * A:如果你创建文件或者文件夹忘了写盘符路径,那么,默认在项目路径下。
    * B:Java中的删除不走回收站。
    * C:要删除一个文件夹,请注意该文件夹内不能包含文件或者文件夹
    */
    public class FileDemo {
    public static void main(String[] args) throws IOException {
    // 创建文件
    // File file = new File("e:\a.txt");
    // System.out.println("createNewFile:" + file.createNewFile());
     
    // 我不小心写成这个样子了
    File file = new File("a.txt");
    System.out.println("createNewFile:" + file.createNewFile());
     
    // 继续玩几个
    File file2 = new File("aaa\bbb\ccc");
    System.out.println("mkdirs:" + file2.mkdirs());
     
    // 删除功能:我要删除a.txt这个文件
    File file3 = new File("a.txt");
    System.out.println("delete:" + file3.delete());
     
    // 删除功能:我要删除ccc这个文件夹
    File file4 = new File("aaa\bbb\ccc");
    System.out.println("delete:" + file4.delete());
     
    // 删除功能:我要删除aaa文件夹
    // File file5 = new File("aaa");
    // System.out.println("delete:" + file5.delete());
     
    File file6 = new File("aaa\bbb");
    File file7 = new File("aaa");
    System.out.println("delete:" + file6.delete());
    System.out.println("delete:" + file7.delete());
    }
    }
    ===========================================================================package cn.itcast_04;
     
    import java.io.File;
     
    /*
    * 重命名功能:public boolean renameTo(File dest)
    * 如果路径名相同,就是改名。
    * 如果路径名不同,就是改名并剪切。
    *
    * 路径以盘符开始:绝对路径 c:\a.txt
    * 路径不以盘符开始:相对路径 a.txt
    */
    public class FileDemo {
    public static void main(String[] args) {
    // 创建一个文件对象
    // File file = new File("林青霞.jpg");
    // // 需求:我要修改这个文件的名称为"东方不败.jpg"
    // File newFile = new File("东方不败.jpg");
    // System.out.println("renameTo:" + file.renameTo(newFile));
     
    File file2 = new File("东方不败.jpg");
    File newFile2 = new File("e:\林青霞.jpg");
    System.out.println("renameTo:" + file2.renameTo(newFile2));
    }
    }
    ==========================================================================package cn.itcast_05;
     
    import java.io.File;
     
    /*
    * 判断功能:
    * public boolean isDirectory():判断是否是目录
    * public boolean isFile():判断是否是文件
    * public boolean exists():判断是否存在
    * public boolean canRead():判断是否可读
    * public boolean canWrite():判断是否可写
    * public boolean isHidden():判断是否隐藏
    */
    public class FileDemo {
    public static void main(String[] args) {
    // 创建文件对象
    File file = new File("a.txt");
     
    System.out.println("isDirectory:" + file.isDirectory());// false
    System.out.println("isFile:" + file.isFile());// true
    System.out.println("exists:" + file.exists());// true
    System.out.println("canRead:" + file.canRead());// true
    System.out.println("canWrite:" + file.canWrite());// true
    System.out.println("isHidden:" + file.isHidden());// false
    }
    }
     
    ========================================================
    package cn.itcast_06;
     
    import java.io.File;
    import java.text.SimpleDateFormat;
    import java.util.Date;
     
    /*
    * 获取功能:
    * public String getAbsolutePath():获取绝对路径
    * public String getPath():获取相对路径
    * public String getName():获取名称
    * public long length():获取长度。字节数
    * public long lastModified():获取最后一次的修改时间,毫秒值
    */
    public class FileDemo {
    public static void main(String[] args) {
    // 创建文件对象
    File file = new File("demo\test.txt");
     
    System.out.println("getAbsolutePath:" + file.getAbsolutePath());
    System.out.println("getPath:" + file.getPath());
    System.out.println("getName:" + file.getName());
    System.out.println("length:" + file.length());
    System.out.println("lastModified:" + file.lastModified());
     
    // 1416471971031
    Date d = new Date(1416471971031L);
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String s = sdf.format(d);
    System.out.println(s);
    }
    }
    ===========================================================================package cn.itcast_07;
     
    import java.io.File;
     
    /*
    * 获取功能:
    * public String[] list():获取指定目录下的所有文件或者文件夹的名称数组
    * public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组
    */
    public class FileDemo {
    public static void main(String[] args) {
    // 指定一个目录
    File file = new File("e:\");
     
    // public String[] list():获取指定目录下的所有文件或者文件夹的名称数组
    String[] strArray = file.list();
    for (String s : strArray) {
    System.out.println(s);
    }
    System.out.println("------------");
     
    // public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组
    File[] fileArray = file.listFiles();
    for (File f : fileArray) {
    System.out.println(f.getName());
    }
    }
    }
    test
    新建文件夹
    新建文本文档.txt
    file:1470298076394
    E:demo est
    E:demo新建文件夹
    E:demo新建文本文档.txt
     
    $RECYCLE.BIN
    animal.jar
    big data
    big data.txt
    job English
    software
    System Volume Information
    tu.jpg
    VOA
    xunleiyingying
    大数据学习笔记
    讯杰工作
    ------------
    $RECYCLE.BIN
    animal.jar
    big data
    big data.txt
    job English
    software
    System Volume Information
    tu.jpg
    VOA
    xunleiyingying
    大数据学习笔记
    讯杰工作
     
    ====================================
    package cn.itcast_08;
     
    import java.io.File;
     
    /*
    * 判断E盘目录下是否有后缀名为.jpg的文件,如果有,就输出此文件名称
    *
    * 分析:
    * A:封装e判断目录
    * B:获取该目录下所有文件或者文件夹的File数组
    * C:遍历该File数组,得到每一个File对象,然后判断
    * D:是否是文件
    * 是:继续判断是否以.jpg结尾
    * 是:就输出该文件名称
    * 否:不搭理它
    * 否:不搭理它
    */
    public class FileDemo {
    public static void main(String[] args) {
    // 封装e判断目录
    File file = new File("e:\");
     
    // 获取该目录下所有文件或者文件夹的File数组
    File[] fileArray = file.listFiles();
     
    // 遍历该File数组,得到每一个File对象,然后判断
    for (File f : fileArray) {
    // 是否是文件
    if (f.isFile()) {
    // 继续判断是否以.jpg结尾
    if (f.getName().endsWith(".jpg")) {
    // 就输出该文件名称
    System.out.println(f.getName());
    }
    }
    }
    }
    }
    ==========================================================
    package cn.itcast_08;
     
    import java.io.File;
    import java.io.FilenameFilter;
     
    /*
    * 判断E盘目录下是否有后缀名为.jpg的文件,如果有,就输出此文件名称
    * A:先获取所有的,然后遍历的时候,依次判断,如果满足条件就输出。
    * B:获取的时候就已经是满足条件的了,然后输出即可。
    *
    * 要想实现这个效果,就必须学习一个接口:文件名称过滤器
    * public String[] list(FilenameFilter filter)
    * public File[] listFiles(FilenameFilter filter)
    */
    public class FileDemo2 {
    public static void main(String[] args) {
    // 封装e判断目录
    File file = new File("e:\");
     
    // 获取该目录下所有文件或者文件夹的String数组
    // public String[] list(FilenameFilter filter)
    String[] strArray = file.list(new FilenameFilter() {
    @Override
    public boolean accept(File dir, String name) {
    // return false;
    // return true;
    // 通过这个测试,我们就知道了,到底把这个文件或者文件夹的名称加不加到数组中,取决于这里的返回值是true还是false
    // 所以,这个的true或者false应该是我们通过某种判断得到的
    // System.out.println(dir + "---" + name);
    // File file = new File(dir, name);
    // // System.out.println(file);
    // boolean flag = file.isFile();
    // boolean flag2 = name.endsWith(".jpg");
    // return flag && flag2;
    return new File(dir, name).isFile() && name.endsWith(".jpg");
    }
    });
     
    // 遍历
    for (String s : strArray) {
    System.out.println(s);
    }
    }
    }
     
    =======================================================
    package cn.itcast_09;
     
    import java.io.File;
     
    /*
    * 需求:把E:评书三国演义下面的视频名称修改为
    * 00?_介绍.avi
    *
    * 思路:
    * A:封装目录
    * B:获取该目录下所有的文件的File数组
    * C:遍历该File数组,得到每一个File对象
    * D:拼接一个新的名称,然后重命名即可。
    */
    public class FileDemo {
    public static void main(String[] args) {
    // 封装目录
    File srcFolder = new File("E:\评书\三国演义");
     
    // 获取该目录下所有的文件的File数组
    File[] fileArray = srcFolder.listFiles();
     
    // 遍历该File数组,得到每一个File对象
    for (File file : fileArray) {
    // System.out.println(file);
    // E:评书三国演义三国演义_001_[评书网-今天很高兴,明天就IO了]_桃园三结义.avi
    // 改后:E:评书三国演义01_桃园三结义.avi
    String name = file.getName(); // 三国演义_001_[评书网-今天很高兴,明天就IO了]_桃园三结义.avi
     
    int index = name.indexOf("_");
    String numberString = name.substring(index + 1, index + 4);
    // System.out.println(numberString);
     
    // int startIndex = name.lastIndexOf('_');
    // int endIndex = name.lastIndexOf('.');
    // String nameString = name.substring(startIndex + 1, endIndex);
    // System.out.println(nameString);
    int endIndex = name.lastIndexOf('_');
    String nameString = name.substring(endIndex);
     
    String newName = numberString.concat(nameString); // 001_桃园三结义.avi
    // System.out.println(newName);
     
    File newFile = new File(srcFolder, newName); // E:\评书\三国演义\001_桃园三结义.avi
     
    // 重命名即可
    file.renameTo(newFile);
    }
    }
    }
     二.
    package cn.itcast_01;
     
    /*
    * 递归:方法定义中调用方法本身的现象
    *
    * 方法的嵌套调用,这不是递归。
    * Math.max(Math.max(a,b),c);
    *
    * public void show(int n) {
    * if(n <= 0) {
    * System.exit(0);
    * }
    * System.out.println(n);
    * show(--n);
    * }
    *
    * 注意事项:
    * A:递归一定要有出口,否则就是死递归
    * B:递归的次数不能太多,否则就内存溢出
    * C:构造方法不能递归使用
    *
    * 举例:
    * A:从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:
    * 从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:
    * 从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:
    * 从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:
    * ...
    * 庙挂了,或者山崩了
    * B:学编程 -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费
    * 学编程 -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费
    * 学编程 -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费
    * 学编程 -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费
    * ...
    * 娶不到媳妇或者生不了娃娃
    */
    public class DiGuiDemo {
    // public DiGuiDemo() {
    // DiGuiDemo();
    // }
    }
    =====================================================
    package cn.itcast_02;
     
    /*
    * 需求:请用代码实现求5的阶乘。
    * 下面的知识要知道:
    * 5! = 1*2*3*4*5
    * 5! = 5*4!
    *
    * 有几种方案实现呢?
    * A:循环实现
    * B:递归实现
    * a:做递归要写一个方法
    * b:出口条件
    * c:规律
    */
    public class DiGuiDemo {
    public static void main(String[] args) {
    int jc = 1;
    for (int x = 2; x <= 5; x++) {
    jc *= x;
    }
    System.out.println("5的阶乘是:" + jc);
     
    System.out.println("5的阶乘是:"+jieCheng(5));
    }
     
    /*
    * 做递归要写一个方法:
    * 返回值类型:int
    * 参数列表:int n
    * 出口条件:
    * if(n == 1) {return 1;}
    * 规律:
    * if(n != 1) {return n*方法名(n-1);}
    */
    public static int jieCheng(int n){
    if(n==1){
    return 1;
    }else {
    return n*jieCheng(n-1);
    }
    }
    }
    ===============================================
    package cn.itcast_02;
     
    /*
    * 有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问第二十个月的兔子对数为多少?
    * 分析:我们要想办法找规律
    * 兔子对数
    * 第一个月: 1
    * 第二个月: 1
    * 第三个月: 2
    * 第四个月: 3
    * 第五个月: 5
    * 第六个月: 8
    * ...
    *
    * 由此可见兔子对象的数据是:
    * 1,1,2,3,5,8...
    * 规则:
    * A:从第三项开始,每一项是前两项之和
    * B:而且说明前两项是已知的
    *
    * 如何实现这个程序呢?
    * A:数组实现
    * B:变量的变化实现
    * C:递归实现
    *
    * 假如相邻的两个月的兔子对数是a,b
    * 第一个相邻的数据:a=1,b=1
    * 第二个相邻的数据:a=1,b=2
    * 第三个相邻的数据:a=2,b=3
    * 第四个相邻的数据:a=3,b=5
    * 看到了:下一次的a是以前的b,下一次是以前的a+b
    */
    public class DiGuiDemo2 {
    public static void main(String[] args) {
    // 定义一个数组
    int[] arr = new int[20];
    arr[0] = 1;
    arr[1] = 1;
    // arr[2] = arr[0] + arr[1];
    // arr[3] = arr[1] + arr[2];
    // ...
    for (int x = 2; x < arr.length; x++) {
    arr[x] = arr[x - 2] + arr[x - 1];
    }
    System.out.println(arr[19]);// 6765
    System.out.println("----------------");
     
    int a = 1;
    int b = 1;
    for (int x = 0; x < 18; x++) {
    // 临时变量存储上一次的a
    int temp = a;
    a = b;
    b = temp + b;
    }
    System.out.println(b);
    System.out.println("----------------");
     
    System.out.println(fib(20));
    }
     
    /*
    * 方法: 返回值类型:int 参数列表:int n 出口条件: 第一个月是1,第二个月是1 规律: 从第三个月开始,每一个月是前两个月之和
    */
    public static int fib(int n) {
    if (n == 1 || n == 2) {
    return 1;
    } else {
    return fib(n - 1) + fib(n - 2);
    }
    }
    }
     
    6765
    ===============
    6765
    ===============
    6765
    =========================================================
    package cn.itcast_03;
     
    import java.io.File;
     
    /*
    * 需求:递归删除带内容的目录
    *
    * 目录我已经给定:demo
    *
    * 分析:
    * A:封装目录
    * B:获取该目录下的所有文件或者文件夹的File数组
    * C:遍历该File数组,得到每一个File对象
    * D:判断该File对象是否是文件夹
    * 是:回到B
    * 否:就删除
    */
    public class FileDeleteDemo {
    public static void main(String[] args) {
    // 封装目录
    File srcFolder = new File("demo");
    // 递归实现
    deleteFolder(srcFolder);
    }
     
    private static void deleteFolder(File srcFolder) {
    // 获取该目录下的所有文件或者文件夹的File数组
    File[] fileArray = srcFolder.listFiles();
     
    if (fileArray != null) {
    // 遍历该File数组,得到每一个File对象
    for (File file : fileArray) {
    // 判断该File对象是否是文件夹
    if (file.isDirectory()) {
    deleteFolder(file);
    } else {
    System.out.println(file.getName() + "---" + file.delete());
    }
    }
     
    System.out.println(srcFolder.getName() + "---" + srcFolder.delete());
    }
    }
     
    ==========================================================
    package cn.itcast_03;
     
    import java.io.File;
     
    /*
    * 需求:请大家把E:JavaSE目录下所有的java结尾的文件的绝对路径给输出在控制台。
    *
    * 分析:
    * A:封装目录
    * B:获取该目录下所有的文件或者文件夹的File数组
    * C:遍历该File数组,得到每一个File对象
    * D:判断该File对象是否是文件夹
    * 是:回到B
    * 否:继续判断是否以.java结尾
    * 是:就输出该文件的绝对路径
    * 否:不搭理它
    */
    public class FilePathDemo {
    public static void main(String[] args) {
    // 封装目录
    File srcFolder = new File("E:\JavaSE");
     
    // 递归功能实现
    getAllJavaFilePaths(srcFolder);
    }
     
    private static void getAllJavaFilePaths(File srcFolder) {
    // 获取该目录下所有的文件或者文件夹的File数组
    File[] fileArray = srcFolder.listFiles();
     
    // 遍历该File数组,得到每一个File对象
    for (File file : fileArray) {
    // 判断该File对象是否是文件夹
    if (file.isDirectory()) {
    getAllJavaFilePaths(file);
    } else {
    // 继续判断是否以.java结尾
    if (file.getName().endsWith(".java")) {
    // 就输出该文件的绝对路径
    System.out.println(file.getAbsolutePath());
    }
    }
    }
    }
    }
    }
    =======================================================================
    package cn.itcast_01;
     
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
     
    /*
    * IO流的分类:
    * 流向:
    * 输入流 读取数据
    * 输出流 写出数据
    * 数据类型:
    * 字节流
    * 字节输入流 读取数据 InputStream
    * 字节输出流 写出数据 OutputStream
    * 字符流
    * 字符输入流 读取数据 Reader
    * 字符输出流 写出数据 Writer
    *
    * 注意:一般我们在探讨IO流的时候,如果没有明确说明按哪种分类来说,默认情况下是按照数据类型来分的。
    *
    * 需求:我要往一个文本文件中输入一句话:"hello,io"
    *
    * 分析:
    * A:这个操作最好是采用字符流来做,但是呢,字符流是在字节流之后才出现的,所以,今天我先讲解字节流如何操作。
    * B:由于我是要往文件中写一句话,所以我们要采用字节输出流。
    *
    * 通过上面的分析后我们知道要使用:OutputStream
    * 但是通过查看API,我们发现该流对象是一个抽象类,不能实例化。
    * 所以,我们要找一个具体的子类。
    * 而我们要找的子类是什么名字的呢?这个时候,很简单,我们回想一下,我们是不是要往文件中写东西。
    * 文件是哪个单词:File
    * 然后用的是字节输出流,联起来就是:FileOutputStream
    * 注意:每种基类的子类都是以父类名作为后缀名。
    * XxxOutputStream
    * XxxInputStream
    * XxxReader
    * XxxWriter
    * 查看FileOutputStream的构造方法:
    * FileOutputStream(File file)
    * FileOutputStream(String name)
    *
    * 字节输出流操作步骤:
    * A:创建字节输出流对象
    * B:写数据
    * C:释放资源
    */
    public class FileOutputStreamDemo {
    public static void main(String[] args) throws IOException {
    // 创建字节输出流对象
    // FileOutputStream(File file)
    // File file = new File("fos.txt");
    // FileOutputStream fos = new FileOutputStream(file);
    // FileOutputStream(String name)
    FileOutputStream fos = new FileOutputStream("fos.txt");
    /*
    * 创建字节输出流对象了做了几件事情:
    * A:调用系统功能去创建文件
    * B:创建fos对象
    * C:把fos对象指向这个文件
    */
     
    //写数据
    fos.write("hello,IO".getBytes());
    fos.write("java".getBytes());
     
    //释放资源
    //关闭此文件输出流并释放与此流有关的所有系统资源。
    fos.close();
    /*
    * 为什么一定要close()呢?
    * A:让流对象变成垃圾,这样就可以被垃圾回收器回收了
    * B:通知系统去释放跟该文件相关的资源
    */
    //java.io.IOException: Stream Closed
    //fos.write("java".getBytes());
    }
    }
    ===========================================================================package cn.itcast_01;
     
    import java.io.FileOutputStream;
    import java.io.IOException;
     
    /*
    * 字节输出流操作步骤:
    * A:创建字节输出流对象
    * B:调用write()方法
    * C:释放资源
    *
    * public void write(int b):写一 个字节
    * public void write(byte[] b):写一个字节数组
    * public void write(byte[] b,int off,int len):写一个字节数组的一部分
    */
    public class FileOutputStreamDemo2 {
    public static void main(String[] args) throws IOException {
    // 创建字节输出流对象
    // OutputStream os = new FileOutputStream("fos2.txt"); // 多态
    FileOutputStream fos = new FileOutputStream("fos2.txt");
     
    // 调用write()方法
    //fos.write(97); / /97 -- 底层二进制数据 -- 通过记事本打开 -- 找97对应的字符值 -- a
    // fos.write(57);
    // fos.write(55);
     
    //public void write(byte[] b):写一个字节数组
    byte[] bys={97,98,99,100,101};
    fos.write(bys);
     
    //public void write(byte[] b,int off,int len):写一个字节数组的一部分
    fos.write(bys,1,3);
     
    //释放资源
    fos.close();
    }
    }
    ================================================================
    package cn.itcast_01;
     
    import java.io.FileOutputStream;
    import java.io.IOException;
     
    /*
    * 如何实现数据的换行?
    * 为什么现在没有换行呢?因为你值写了字节数据,并没有写入换行符号。
    * 如何实现呢?写入换行符号即可呗。
    * 刚才我们看到了有写文本文件打开是可以的,通过windows自带的那个不行,为什么呢?
    * 因为不同的系统针对不同的换行符号识别是不一样的?
    * windows:
    * linux:
    * Mac:
    * 而一些常见的个高级记事本,是可以识别任意换行符号的。
    *
    * 如何实现数据的追加写入?
    * 用构造方法带第二个参数是true的情况即可
    */
    public class FileOutputStreamDemo3 {
    public static void main(String[] args) throws IOException {
    // 创建字节输出流对象
    // FileOutputStream fos = new FileOutputStream("fos3.txt");
    // 创建一个向具有指定 name 的文件中写入数据的输出文件流。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。
    FileOutputStream fos = new FileOutputStream("fos3.txt", true);
     
    // 写数据
    for (int x = 0; x < 10; x++) {
    fos.write(("hello" + x).getBytes());
    fos.write(" ".getBytes());
    }
     
    // 释放资源
    fos.close();
    }
    }
    ==================================================================
    package cn.itcast_01;
     
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
     
    /*
    * 加入异常处理的字节输出流操作
    */
    public class FileOutputStreamDemo4 {
    public static void main(String[] args) {
    // 分开做异常处理
    // FileOutputStream fos = null;
    // try {
    // fos = new FileOutputStream("fos4.txt");
    // } catch (FileNotFoundException e) {
    // e.printStackTrace();
    // }
    //
    // try {
    // fos.write("java".getBytes());
    // } catch (IOException e) {
    // e.printStackTrace();
    // }
    //
    // try {
    // fos.close();
    // } catch (IOException e) {
    // e.printStackTrace();
    // }
     
    // 一起做异常处理
    // try {
    // FileOutputStream fos = new FileOutputStream("fos4.txt");
    // fos.write("java".getBytes());
    // fos.close();
    // } catch (FileNotFoundException e) {
    // e.printStackTrace();
    // } catch (IOException e) {
    // e.printStackTrace();
    // }
     
    // 改进版
    // 为了在finally里面能够看到该对象就必须定义到外面,为了访问不出问题,还必须给初始化值
    FileOutputStream fos = null;
    try {
    // fos = new FileOutputStream("z:\fos4.txt");
    fos = new FileOutputStream("fos4.txt");
    fos.write("java".getBytes());
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    // 如果fos不是null,才需要close()
    if (fos != null) {
    // 为了保证close()一定会执行,就放到这里了
    try {
    fos.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
    }
    }
    ===========================================================
    package cn.itcast_02;
     
    import java.io.FileInputStream;
    import java.io.IOException;
     
    /*
    * 字节输入流操作步骤:
    * A:创建字节输入流对象
    * B:调用read()方法读取数据,并把数据显示在控制台
    * C:释放资源
    *
    * 读取数据的方式:
    * A:int read():一次读取一个字节
    * B:int read(byte[] b):一次读取一个字节数组
    */
    public class FileInputStreamDemo {
    public static void main(String[] args) throws IOException {
    // FileInputStream(String name)
    // FileInputStream fis = new FileInputStream("fis.txt");
    FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java");
     
    // // 调用read()方法读取数据,并把数据显示在控制台
    // // 第一次读取
    // int by = fis.read();
    // System.out.println(by);
    // System.out.println((char) by);
    //
    // // 第二次读取
    // by = fis.read();
    // System.out.println(by);
    // System.out.println((char) by);
    //
    // // 第三次读取
    // by = fis.read();
    // System.out.println(by);
    // System.out.println((char) by);
    // // 我们发现代码的重复度很高,所以我们要用循环改进
    // // 而用循环,最麻烦的事情是如何控制循环判断条件呢?
    // // 第四次读取
    // by = fis.read();
    // System.out.println(by);
    // // 第五次读取
    // by = fis.read();
    // System.out.println(by);
    // //通过测试,我们知道如果你读取的数据是-1,就说明已经读取到文件的末尾了
     
    // 用循环改进
    // int by = fis.read();
    // while (by != -1) {
    // System.out.print((char) by);
    // by = fis.read();
    // }
     
    // 最终版代码
    int by = 0;
    // 读取,赋值,判断
    while ((by = fis.read()) != -1) {
    System.out.print((char) by);
    }
     
    // 释放资源
    fis.close();
    }
    }
    ===============================================
    package cn.itcast_02;
     
    import java.io.FileInputStream;
    import java.io.IOException;
     
    /*
    * 一次读取一个字节数组:int read(byte[] b)
    * 返回值其实是实际读取的字节个数。
    */
    public class FileInputStreamDemo2 {
    public static void main(String[] args) throws IOException {
    // 创建字节输入流对象
    // FileInputStream fis = new FileInputStream("fis2.txt");
    FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java");
     
    // 读取数据
    // 定义一个字节数组
    // 第一次读取
    // byte[] bys = new byte[5];
    // int len = fis.read(bys);
    // // System.out.println(len);
    // // System.out.println(new String(bys));
    // // System.out.println(new String(bys, 0, len));
    // System.out.print(new String(bys, 0, len));
    //
    // // 第二次读取
    // len = fis.read(bys);
    // // System.out.println(len);
    // // System.out.println(new String(bys));
    // // System.out.println(new String(bys, 0, len));
    // System.out.print(new String(bys, 0, len));
    //
    // // 第三次读取
    // len = fis.read(bys);
    // // System.out.println(len);
    // // System.out.println(new String(bys));
    // // System.out.println(new String(bys, 0, len));
    // System.out.print(new String(bys, 0, len));
    //
    // // 第四次读取
    // len = fis.read(bys);
    // // System.out.println(len);
    // // System.out.println(new String(bys, 0, len));
    // System.out.print(new String(bys, 0, len));
    // // 代码重复了,用循环改进
    // // 但是,我不知道结束条件
    // // len = fis.read(bys);
    // // System.out.println(len);
    // // len = fis.read(bys);
    // // System.out.println(len);
    // // 如果读取到的实际长度是-1,就说明没有数据了
     
    // byte[] bys = new byte[115]; // 0
    // int len = 0;
    // while ((len = fis.read(bys)) != -1) {
    // System.out.print(new String(bys, 0, len));
    // // System.out.print(new String(bys)); //千万要带上len的使用
    // }
     
    // 最终版代码
    // 数组的长度一般是1024或者1024的整数倍
    byte[] bys = new byte[1024];
    int len = 0;
    while ((len = fis.read(bys)) != -1) {
    System.out.print(new String(bys, 0, len));
    }
     
    // 释放资源
    fis.close();
    }
    ==========================================
    package cn.itcast_03;
     
    import java.util.Arrays;
     
    /*
    * 计算机是如何识别什么时候该把两个字节转换为一个中文呢?
    * 在计算机中中文的存储分两个字节:
    * 第一个字节肯定是负数。
    * 第二个字节常见的是负数,可能有正数。但是没影响。
    */
    public class StringDemo {
    public static void main(String[] args) {
    // String s = "abcde";
    // // [97, 98, 99, 100, 101]
     
    String s = "我爱你中国";
    // [-50, -46, -80, -82, -60, -29, -42, -48, -71, -6]
     
    byte[] bys = s.getBytes();
    System.out.println(Arrays.toString(bys));
    }
    }
    =======================================
    package cn.itcast_03;
     
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
     
    /*
    * 需求:把e:\哥有老婆.mp4复制到当前项目目录下的copy.mp4中
    *
    * 数据源:
    * e:\哥有老婆.mp4--读取数据--FileInputStream
    * 目的地:
    * copy.mp4--写出数据--FileOutputStream
    */
    public class CopyMp4Demo {
    public static void main(String[] args) throws IOException {
    // 封装数据源
    FileInputStream fis = new FileInputStream("e:\哥有老婆.mp4");
    // 封装目的地
    FileOutputStream fos = new FileOutputStream("copy.mp4");
     
    // 复制数据
    int by = 0;
    while ((by = fis.read()) != -1) {
    fos.write(by);
    }
     
    // 释放资源
    fos.close();
    fis.close();
    }
    }
     
    =========================================================
    package cn.itcast_03;
     
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
     
    /*
    * 需求:把c盘下的a.txt的内容复制到d盘下的b.txt中
    *
    * 数据源:
    * c:\a.txt -- 读取数据-- FileInputStream
    * 目的地:
    * d:\b.txt -- 写出数据 -- FileOutputStream
    */
    public class CopyFileDemo2 {
    public static void main(String[] args) throws IOException {
    // 封装数据源
    FileInputStream fis = new FileInputStream("c:\a.txt");
    // 封装目的地
    FileOutputStream fos = new FileOutputStream("d:\b.txt");
     
    // 复制数据
    int by = 0;
    while ((by = fis.read()) != -1) {
    fos.write(by);
    }
     
    // 释放资源
    fos.close();
    fis.close();
    }
    }
    =====================================================
    package cn.itcast_03;
     
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
     
    /*
    * 复制文本文件。
    *
    * 数据源:从哪里来
    * a.txt -- 读取数据 -- FileInputStream
    *
    * 目的地:到哪里去
    * b.txt -- 写数据 -- FileOutputStream
    *
    * java.io.FileNotFoundException: a.txt (系统找不到指定的文件。)
    *
    * 这一次复制中文没有出现任何问题,为什么呢?
    * 上一次我们出现问题的原因在于我们每次获取到一个字节数据,就把该字节数据转换为了字符数据,然后输出到控制台。
    * 而这一次呢?确实通过IO流读取数据,写到文本文件,你读取一个字节,我就写入一个字节,你没有做任何的转换。
    * 它会自己做转换。
    */
    public class CopyFileDemo {
    public static void main(String[] args) throws IOException {
    // 封装数据源
    FileInputStream fis = new FileInputStream("a.txt");
    // 封装目的地
    FileOutputStream fos = new FileOutputStream("b.txt");
     
    int by = 0;
    while ((by = fis.read()) != -1) {
    fos.write(by);
    }
     
    // 释放资源(先关谁都行)
    fos.close();
    fis.close();
    }
    }
    =====================================================================
    package cn.itcast_04;
     
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
     
    /*
    * 需求:把c:\a.txt内容复制到d:\b.txt中
    *
    * 数据源:
    * c:\a.txt -- 读取数据 -- FileInputStream
    * 目的地:
    * d:\b.txt -- 写出数据 -- FileOutputStream
    */
    public class CopyFileDemo {
    public static void main(String[] args) throws IOException {
    // 封装数据源
    FileInputStream fis = new FileInputStream("c:\a.txt");
    FileOutputStream fos = new FileOutputStream("d:\b.txt");
     
    // 复制数据
    byte[] bys = new byte[1024];
    int len = 0;
    while ((len = fis.read(bys)) != -1) {
    fos.write(bys, 0, len);
    将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
    }
     
    // 释放资源
    fos.close();
    fis.close();
    }
    }
    ====================================================
    package cn.itcast_04;
     
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
     
    /*
    * 需求:把e:\哥有老婆.mp4复制到当前项目目录下的copy.mp4中
    *
    * 数据源:
    * e:\哥有老婆.mp4--读取数据--FileInputStream
    * 目的地:
    * copy.mp4--写出数据--FileOutputStream
    */
    public class CopyMp4Demo {
    public static void main(String[] args) throws IOException {
    // 封装数据源
    FileInputStream fis = new FileInputStream("e:\哥有老婆.mp4");
    // 封装目的地
    FileOutputStream fos = new FileOutputStream("copy.mp4");
     
    // 复制数据
    byte[] bys = new byte[1024];
    int len = 0;
    while ((len = fis.read(bys)) != -1) {
    fos.write(bys, 0, len);
    }
     
    // 释放资源
    fos.close();
    fis.close();
    }
    }
    ======================================================
    package cn.itcast_05;
     
    import java.io.BufferedInputStream;
    import java.io.FileInputStream;
    import java.io.IOException;
     
    /*
    * 注意:虽然我们有两种方式可以读取,但是,请注意,这两种方式针对同一个对象在一个代码中只能使用一个。
    */
    public class BufferedInputStreamDemo {
    public static void main(String[] args) throws IOException {
    // BufferedInputStream(InputStream in)
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
    "bos.txt"));
     
    // 读取数据
    // int by = 0;
    // while ((by = bis.read()) != -1) {
    // System.out.print((char) by);
    // }
    // System.out.println("---------");
     
    byte[] bys = new byte[1024];
    int len = 0;
    while ((len = bis.read(bys)) != -1) {
    System.out.print(new String(bys, 0, len));
    }
     
    // 释放资源
    bis.close();
    }
    }
    ===========================================================================package cn.itcast_05;
     
    import java.io.BufferedOutputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
     
    /*
    * 通过定义数组的方式确实比以前一次读取一个字节的方式快很多,所以,看来有一个缓冲区还是非常好的。
    * 既然是这样的话,那么,java开始在设计的时候,它也考虑到了这个问题,就专门提供了带缓冲区的字节类。
    * 这种类被称为:缓冲区类(高效类)
    * 写数据:BufferedOutputStream
    * 读数据:BufferedInputStream
    *
    * 构造方法可以指定缓冲区的大小,但是我们一般用不上,因为默认缓冲区大小就足够了。
    *
    * 为什么不传递一个具体的文件或者文件路径,而是传递一个OutputStream对象呢?
    * 原因很简单,字节缓冲区流仅仅提供缓冲区,为高效而设计的。但是呢,真正的读写操作还得靠基本的流对象实现。
    */
    public class BufferedOutputStreamDemo {
    public static void main(String[] args) throws IOException {
    // BufferedOutputStream(OutputStream out)
    创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
    // FileOutputStream fos = new FileOutputStream("bos.txt");
    // BufferedOutputStream bos = new BufferedOutputStream(fos);
    // 简单写法
    BufferedOutputStream bos = new BufferedOutputStream(
    new FileOutputStream("bos.txt"));
     
    // 写数据
    bos.write("hello".getBytes());
    // 释放资源
    bos.close();
    }
    }
    ==========================================================================
    package cn.itcast_06;
     
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
     
    /*
    * 需求:把e:\哥有老婆.mp4复制到当前项目目录下的copy.mp4中
    *
    * 字节流四种方式复制文件:
    * 基本字节流一次读写一个字节: 共耗时:117235毫秒
    * 基本字节流一次读写一个字节数组: 共耗时:156毫秒
    * 高效字节流一次读写一个字节: 共耗时:1141毫秒
    * 高效字节流一次读写一个字节数组: 共耗时:47毫秒
    */
    public class CopyMp4Demo {
    public static void main(String[] args) throws IOException {
    long start = System.currentTimeMillis();
    // method1("e:\哥有老婆.mp4", "copy1.mp4");
    // method2("e:\哥有老婆.mp4", "copy2.mp4");
    // method3("e:\哥有老婆.mp4", "copy3.mp4");
    method4("e:\哥有老婆.mp4", "copy4.mp4");
    long end = System.currentTimeMillis();
    System.out.println("共耗时:" + (end - start) + "毫秒");
    }
     
    // 高效字节流一次读写一个字节数组:
    public static void method4(String srcString, String destString)
    throws IOException {
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
    srcString));
    BufferedOutputStream bos = new BufferedOutputStream(
    new FileOutputStream(destString));
     
    byte[] bys = new byte[1024];
    int len = 0;
    while ((len = bis.read(bys)) != -1) { //从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。
    bos.write(bys, 0, len);
    }
     
    bos.close();
    bis.close();
    }
     
    // 高效字节流一次读写一个字节:
    public static void method3(String srcString, String destString)
    throws IOException {
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
    srcString));
    BufferedOutputStream bos = new BufferedOutputStream(
    new FileOutputStream(destString));
     
    int by = 0;
    while ((by = bis.read()) != -1) {
    bos.write(by);
     
    }
     
    bos.close();
    bis.close();
    }
     
    // 基本字节流一次读写一个字节数组
    public static void method2(String srcString, String destString)
    throws IOException {
    FileInputStream fis = new FileInputStream(srcString);
    FileOutputStream fos = new FileOutputStream(destString);
     
    byte[] bys = new byte[1024];
    int len = 0;
    while ((len = fis.read(bys)) != -1) {
    fos.write(bys, 0, len);
    }
     
    fos.close();
    fis.close();
    }
     
    // 基本字节流一次读写一个字节
    public static void method1(String srcString, String destString)
    throws IOException {
    FileInputStream fis = new FileInputStream(srcString);
    FileOutputStream fos = new FileOutputStream(destString);
     
    int by = 0;
    while ((by = fis.read()) != -1) {
    fos.write(by);
    }
     
    fos.close();
    fis.close();
    }
    }
     
    二.
    package cn.itcast_01;
     
    import java.io.UnsupportedEncodingException;
    import java.util.Arrays;
     
    /*
    * String(byte[] bytes, String charsetName):通过指定的字符集解码字节数组
    * byte[] getBytes(String charsetName):使用指定的字符集合把字符串编码为字节数组
    *
    * 编码:把看得懂的变成看不懂的
    * String -- byte[]
    *
    * 解码:把看不懂的变成看得懂的
    * byte[] -- String
    *
    * 举例:谍战片(发电报,接电报)
    *
    * 码表:小本子
    * 字符 数值
    *
    * 要发送一段文字:
    * 今天晚上在老地方见
    *
    * 发送端:今 -- 数值 -- 二进制 -- 发出去
    * 接收端:接收 -- 二进制 -- 十进制 -- 数值 -- 字符 -- 今
    *
    * 今天晚上在老地方见
    *
    * 编码问题简单,只要编码解码的格式是一致的。
    */
    public class StringDemo {
    public static void main(String[] args) throws UnsupportedEncodingException {
    String s = "你好";
     
    // String -- byte[] 使用指定的字符集合把字符串编码为字节数组
    byte[] bys = s.getBytes(); // [-60, -29, -70, -61]
    // byte[] bys = s.getBytes("GBK");// [-60, -29, -70, -61]
    // byte[] bys = s.getBytes("UTF-8");// [-28, -67, -96, -27, -91, -67]
    System.out.println(Arrays.toString(bys));//返回指定数组内容的字符串表示形式。字符串表示形式由数组的元素列表组成,括在方括号("[]")中。相邻元素用字符 ", "(逗号加空格)分隔。这些元素通过 String.valueOf(char) 转换为字符串。如果 anull,则返回 "null"
     
     
     
    // byte[] -- String通过指定的字符集解码字节数组
    String ss = new String(bys); // 你好
    // String ss = new String(bys, "GBK"); // 你好
    // String ss = new String(bys, "UTF-8"); // ???
    System.out.println(ss);
    }
    }
    ==================================================
    package cn.itcast_01;
     
    import java.io.FileInputStream;
    import java.io.IOException;
     
    /*
    * 字节流读取中文可能出现的小问题:
    */
    public class FileInputStreamDemo {
    public static void main(String[] args) throws IOException {
    // 创建字节输入流对象
    FileInputStream fis = new FileInputStream("a.txt");
     
    // 读取数据
    // int by = 0;
    // while ((by = fis.read()) != -1) {
    // System.out.print((char) by);
    // }
     
    byte[] bys = new byte[1024];
    int len = 0;
    while ((len = fis.read(bys)) != -1) {
    System.out.print(new String(bys, 0, len));
    }
     
    // 释放资源
    fis.close();
    }
    }
    ===========================
    package cn.itcast_02;
     
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
     
    /*
    * InputStreamReader(InputStream is):用默认的编码读取数据
    * InputStreamReader(InputStream is,String charsetName):用指定的编码读取数据
    */
    InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集
    public class InputStreamReaderDemo {
    public static void main(String[] args) throws IOException {
    // 创建对象
    // InputStreamReader isr = new InputStreamReader(new FileInputStream(
    // "osw.txt"));
     
    // InputStreamReader isr = new InputStreamReader(new FileInputStream(
    // "osw.txt"), "GBK");
     
    InputStreamReader isr = new InputStreamReader(new FileInputStream(
    "osw.txt"), "UTF-8");
     
    // 读取数据
    // 一次读取一个字符
    int ch = 0;
    while ((ch = isr.read()) != -1) {
    System.out.print((char) ch);
    }
     
    // 释放资源
    isr.close();
    }
    }
    =========================================
    package cn.itcast_03;
     
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
     
    /*
    * InputStreamReader的方法:
    * int read():一次读取一个字符
    * int read(char[] chs):一次读取一个字符数组
    */
    public class InputStreamReaderDemo {
    public static void main(String[] args) throws IOException {
    // 创建对象
    InputStreamReader isr = new InputStreamReader(new FileInputStream(
    "StringDemo.java"));
     
    // 一次读取一个字符
    // int ch = 0;
    // while ((ch = isr.read()) != -1) {
    // System.out.print((char) ch);
    // }
     
    // 一次读取一个字符数组
    char[] chs = new char[1024];
    int len = 0;
    while ((len = isr.read(chs)) != -1) {
    System.out.print(new String(chs, 0, len));
    }
     
    // 释放资源
    isr.close();
    }
    }
    =========================================================
    package cn.itcast_03;
     
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStreamWriter;
     
    /*
    * OutputStreamWriter的方法:
    * public void write(int c):写一个字符
    * public void write(char[] cbuf):写一个字符数组
    * public void write(char[] cbuf,int off,int len):写一个字符数组的一部分
    * public void write(String str):写一个字符串
    * public void write(String str,int off,int len):写一个字符串的一部分
    * OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集
    * 面试题:close()和flush()的区别?
    * A:close()关闭流对象,但是先刷新一次缓冲区。关闭之后,流对象不可以继续再使用了。
    * B:flush()仅仅刷新缓冲区,刷新之后,流对象还可以继续使用。
    */
    public class OutputStreamWriterDemo {
    public static void main(String[] args) throws IOException {
    // 创建对象
    OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
    "osw2.txt"));
     
    // 写数据
    // public void write(int c):写一个字符
    // osw.write('a');
    // osw.write(97);
    // 为什么数据没有进去呢?
    // 原因是:字符 = 2字节
    // 文件中数据存储的基本单位是字节。
    // void flush()
     
    // public void write(char[] cbuf):写一个字符数组
    // char[] chs = {'a','b','c','d','e'};
    // osw.write(chs);
     
    // public void write(char[] cbuf,int off,int len):写一个字符数组的一部分
    // osw.write(chs,1,3);
     
    // public void write(String str):写一个字符串
    // osw.write("我爱林青霞");
     
    // public void write(String str,int off,int len):写一个字符串的一部分
    osw.write("我爱林青霞", 2, 3);
     
    // 刷新缓冲区
    osw.flush();
    // osw.write("我爱林青霞", 2, 3);
     
    // 释放资源
    osw.close();
    // java.io.IOException: Stream closed
    // osw.write("我爱林青霞", 2, 3);//报错
    }
    }
    =========================================================
    package cn.itcast_04;
     
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
     
    /*
    * 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中
    *
    * 数据源:
    * a.txt -- 读取数据 -- 字符转换流 -- InputStreamReader
    * 目的地:
    * b.txt -- 写出数据 -- 字符转换流 -- OutputStreamWriter
    */
    public class CopyFileDemo {
    public static void main(String[] args) throws IOException {
    // 封装数据源
    InputStreamReader isr = new InputStreamReader(new FileInputStream(
    "a.txt"));// 读取字节并将其解码为字符
    // 封装目的地
    OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
    "b.txt"));//将要写入流中的字符编码成字节
     
    // 读写数据
    // 方式1
    // int ch = 0;
    // while ((ch = isr.read()) != -1) {
    // osw.write(ch);
    // }
     
    // 方式2
    char[] chs = new char[1024];
    int len = 0;
    while ((len = isr.read(chs)) != -1) {
    osw.write(chs, 0, len);
    // osw.flush();
    }
     
    // 释放资源
    osw.close();
    isr.close();
    }
    }
     
    ===================================================================
    public class FileReader
    用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。
    FileReader 用于读取字符流。要读取原始字节流,请考虑使用 FileInputStream。
    package cn.itcast_04;
     
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
     
    /*
    * 需求:把c:\a.txt内容复制到d:\b.txt中
    *
    * 数据源:
    * c:\a.txt -- FileReader
    * 目的地:
    * d:\b.txt -- FileWriter
    */
    public class CopyFileDemo3 {
    public static void main(String[] args) throws IOException {
    // 封装数据源
    FileReader fr = new FileReader("c:\a.txt");
    // 封装目的地
    FileWriter fw = new FileWriter("d:\b.txt");
     
    // 读写数据
    // int ch = 0;
    int ch;
    while ((ch = fr.read()) != -1) {
    fw.write(ch);
    }
     
    //释放资源
    fw.close();
    fr.close();
    }
    }
    =================================================
    package cn.itcast_05;
     
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
     
    /*BufferedWriter将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
    * 字符缓冲流的特殊方法:
    * BufferedWriter:
    * public void newLine():根据系统来决定换行符
    * BufferedReader:
    * public String readLine():一次读取一行数据
    * 包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
    */
    public class BufferedDemo {
    public static void main(String[] args) throws IOException {
    // write();
    read();
    }
     
    private static void read() throws IOException {
    // 创建字符缓冲输入流对象
    BufferedReader br = new BufferedReader(new FileReader("bw2.txt"));
     
    // public String readLine():一次读取一行数据
    // String line = br.readLine();
    // System.out.println(line);
    // line = br.readLine();
    // System.out.println(line);
     
    // 最终版代码
    String line = null;
    while ((line = br.readLine()) != null) {
    System.out.println(line);
    }
     
    //释放资源
    br.close();
    }
     
    private static void write() throws IOException {
    // 创建字符缓冲输出流对象
    BufferedWriter bw = new BufferedWriter(new FileWriter("bw2.txt"));
    for (int x = 0; x < 10; x++) {
    bw.write("hello" + x);
    // bw.write(" ");
    bw.newLine();
    bw.flush();
    }
    bw.close();
    }
     
    }
    =================================================
    package cn.itcast_05;
     
    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
     
    /*
    * BufferedReader
    * 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
    * 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
    *
    * BufferedReader(Reader in)
    */
    public class BufferedReaderDemo {
    public static void main(String[] args) throws IOException {
    // 创建字符缓冲输入流对象
    BufferedReader br = new BufferedReader(new FileReader("bw.txt"));
     
    // 方式1
    // int ch = 0;
    // while ((ch = br.read()) != -1) {
    // System.out.print((char) ch);
    // }
     
    // 方式2
    char[] chs = new char[1024];
    int len = 0;
    while ((len = br.read(chs)) != -1) {
    System.out.print(new String(chs, 0, len));
    }
     
    // 释放资源
    br.close();
    }
    }
    ==================================================================
    package cn.itcast_05;
     
    import java.io.BufferedWriter;
    import java.io.FileWriter;
    import java.io.IOException;
     
    /*
    * 字符流为了高效读写,也提供了对应的字符缓冲流。
    * BufferedWriter:字符缓冲输出流
    * BufferedReader:字符缓冲输入流
    *
    * BufferedWriter:字符缓冲输出流
    * 将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
    * 可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
    */
    public class BufferedWriterDemo {
    public static void main(String[] args) throws IOException {
    // BufferedWriter(Writer out)
    // BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
    // new FileOutputStream("bw.txt")));
     
    BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
     
    bw.write("hello");
    bw.write("world");
    bw.write("java");
    bw.flush();
     
    bw.close();
    }
    }
    ==============================================
    package cn.itcast_06;
     
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
     
    /*
    * 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中
    *
    * 数据源:
    * a.txt -- 读取数据 -- 字符转换流 -- InputStreamReader -- FileReader -- BufferedReader
    * 目的地:
    * b.txt -- 写出数据 -- 字符转换流 -- OutputStreamWriter -- FileWriter -- BufferedWriter
    */
    public class CopyFileDemo {
    public static void main(String[] args) throws IOException {
    // 封装数据源
    BufferedReader br = new BufferedReader(new FileReader("a.txt"));
    // 封装目的地
    BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
     
    // 两种方式其中的一种一次读写一个字符数组
    char[] chs = new char[1024];
    int len = 0;
    while ((len = br.read(chs)) != -1) {
    bw.write(chs, 0, len);
    bw.flush();
    }
     
    // 释放资源
    bw.close();
    br.close();
    }
    }
    ==========================================
    package cn.itcast_06;
     
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
     
    /*
    * 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中
    *
    * 数据源:
    * a.txt -- 读取数据 -- 字符转换流 -- InputStreamReader -- FileReader -- BufferedReader
    * 目的地:
    * b.txt -- 写出数据 -- 字符转换流 -- OutputStreamWriter -- FileWriter -- BufferedWriter
    */
    public class CopyFileDemo2 {
    public static void main(String[] args) throws IOException {
    // 封装数据源
    BufferedReader br = new BufferedReader(new FileReader("a.txt"));
    // 封装目的地
    BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
     
    // 读写数据
    String line = null;
    while ((line = br.readLine()) != null) {
    bw.write(line);
    bw.newLine();
    bw.flush();
    }
     
    // 释放资源
    bw.close();
    br.close();
    }
    }
    ======================================================
    package cn.itcast_01;
     
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
     
    /*
    * 复制文本文件
    *
    * 分析:
    * 复制数据,如果我们知道用记事本打开并能够读懂,就用字符流,否则用字节流。
    * 通过该原理,我们知道我们应该采用字符流更方便一些。
    * 而字符流有5种方式,所以做这个题目我们有5种方式。推荐掌握第5种。
    * 数据源:
    * c:\a.txt -- FileReader -- BufferdReader
    * 目的地:
    * d:\b.txt -- FileWriter -- BufferedWriter
    */
    public class CopyFileDemo {
    public static void main(String[] args) throws IOException {
    String srcString = "c:\a.txt";
    String destString = "d:\b.txt";
    // method1(srcString, destString);
    // method2(srcString, destString);
    // method3(srcString, destString);
    // method4(srcString, destString);
    method5(srcString, destString);
    }
     
    // 字符缓冲流一次读写一个字符串
    private static void method5(String srcString, String destString)
    throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(srcString));
    BufferedWriter bw = new BufferedWriter(new FileWriter(destString));
     
    String line = null;
    while ((line = br.readLine()) != null) {
    bw.write(line);
    bw.newLine();
    bw.flush();
    }
     
    bw.close();
    br.close();
    }
     
    // 字符缓冲流一次读写一个字符数组
    private static void method4(String srcString, String destString)
    throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(srcString));
    BufferedWriter bw = new BufferedWriter(new FileWriter(destString));
     
    char[] chs = new char[1024];
    int len = 0;
    while ((len = br.read(chs)) != -1) {
    bw.write(chs, 0, len);
    }
     
    bw.close();
    br.close();
    }
     
    // 字符缓冲流一次读写一个字符
    private static void method3(String srcString, String destString)
    throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(srcString));
    BufferedWriter bw = new BufferedWriter(new FileWriter(destString));
     
    int ch = 0;
    while ((ch = br.read()) != -1) {
    bw.write(ch);
    }
     
    bw.close();
    br.close();
    }
     
    // 基本字符流一次读写一个字符数组
    private static void method2(String srcString, String destString)
    throws IOException {
    FileReader fr = new FileReader(srcString);
    FileWriter fw = new FileWriter(destString);
     
    char[] chs = new char[1024];
    int len = 0;
    while ((len = fr.read(chs)) != -1) {
    fw.write(chs, 0, len);
    }
     
    fw.close();
    fr.close();
    }
     
    // 基本字符流一次读写一个字符
    private static void method1(String srcString, String destString)
    throws IOException {
    FileReader fr = new FileReader(srcString);
    FileWriter fw = new FileWriter(destString);
     
    int ch = 0;
    while ((ch = fr.read()) != -1) {
    fw.write(ch);
    }
     
    fw.close();
    fr.close();
    }
    }
    ===================================================
    package cn.itcast_01;
     
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
     
    /*
    * 复制图片
    *
    * 分析:
    * 复制数据,如果我们知道用记事本打开并能够读懂,就用字符流,否则用字节流。
    * 通过该原理,我们知道我们应该采用字节流。
    * 而字节流有4种方式,所以做这个题目我们有4种方式。推荐掌握第4种。
    *
    * 数据源:
    * c:\a.jpg -- FileInputStream -- BufferedInputStream
    * 目的地:
    * d:\b.jpg -- FileOutputStream -- BufferedOutputStream
    */
    public class CopyImageDemo {
    public static void main(String[] args) throws IOException {
    // 使用字符串作为路径
    // String srcString = "c:\a.jpg";
    // String destString = "d:\b.jpg";
    // 使用File对象做为参数
    File srcFile = new File("c:\a.jpg");
    File destFile = new File("d:\b.jpg");
     
    // method1(srcFile, destFile);
    // method2(srcFile, destFile);
    // method3(srcFile, destFile);
    method4(srcFile, destFile);
    }
     
    // 字节缓冲流一次读写一个字节数组
    private static void method4(File srcFile, File destFile) throws IOException {
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
    srcFile));
    BufferedOutputStream bos = new BufferedOutputStream(
    new FileOutputStream(destFile));
     
    byte[] bys = new byte[1024];
    int len = 0;
    while ((len = bis.read(bys)) != -1) {
    bos.write(bys, 0, len);
    }
     
    bos.close();
    bis.close();
    }
     
    // 字节缓冲流一次读写一个字节
    private static void method3(File srcFile, File destFile) throws IOException {
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
    srcFile));
    BufferedOutputStream bos = new BufferedOutputStream(
    new FileOutputStream(destFile));
     
    int by = 0;
    while ((by = bis.read()) != -1) {
    bos.write(by);
    }
     
    bos.close();
    bis.close();
    }
     
    // 基本字节流一次读写一个字节数组
    private static void method2(File srcFile, File destFile) throws IOException {
    FileInputStream fis = new FileInputStream(srcFile);
    FileOutputStream fos = new FileOutputStream(destFile);
     
    byte[] bys = new byte[1024];
    int len = 0;
    while ((len = fis.read(bys)) != -1) {
    fos.write(bys, 0, len);
    }
     
    fos.close();
    fis.close();
    }
     
    // 基本字节流一次读写一个字节
    private static void method1(File srcFile, File destFile) throws IOException {
    FileInputStream fis = new FileInputStream(srcFile);
    FileOutputStream fos = new FileOutputStream(destFile);
     
    int by = 0;
    while ((by = fis.read()) != -1) {
    fos.write(by);
    }
     
    fos.close();
    fis.close();
    }
    }
    ===========================================================================
    package cn.itcast_02;
     
    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Random;
     
    /*
    * 需求:我有一个文本文件中存储了几个名称,请大家写一个程序实现随机获取一个人的名字。
    *
    * 分析:
    * A:把文本文件中的数据存储到集合中
    * B:随机产生一个索引
    * C:根据该索引获取一个值
    */
    public class GetName {
    public static void main(String[] args) throws IOException {
    // 把文本文件中的数据存储到集合中
    BufferedReader br = new BufferedReader(new FileReader("b.txt"));
    ArrayList<String> array = new ArrayList<String>();
    String line = null;
    while ((line = br.readLine()) != null) {
    array.add(line);
    }
    br.close();
     
    // 随机产生一个索引
    Random r = new Random();
    int index = r.nextInt(array.size());
     
    // 根据该索引获取一个值
    String name = array.get(index);
    System.out.println("该幸运者是:" + name);
    }
    }
    ==========================================
    package cn.itcast_02;
     
    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    import java.util.ArrayList;
     
    /*
    * 需求:从文本文件中读取数据(每一行为一个字符串数据)到集合中,并遍历集合
    *
    * 分析:
    * 通过题目的意思我们可以知道如下的一些内容,
    * 数据源是一个文本文件。
    * 目的地是一个集合。
    * 而且元素是字符串。
    *
    * 数据源:
    * b.txt -- FileReader -- BufferedReader
    * 目的地:
    * ArrayList<String>
    */
    public class FileToArrayListDemo {
    public static void main(String[] args) throws IOException {
    // 封装数据源
    BufferedReader br = new BufferedReader(new FileReader("b.txt"));
    // 封装目的地(创建集合对象)
    ArrayList<String> array = new ArrayList<String>();
     
    // 读取数据存储到集合中
    String line = null;
    while ((line = br.readLine()) != null) {
    array.add(line);
    }
     
    // 释放资源
    br.close();
     
    // 遍历集合
    for (String s : array) {
    System.out.println(s);
    }
    }
    }
    =============================================================
    package cn.itcast_02;
     
    import java.io.BufferedWriter;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.util.ArrayList;
     
    /*
    * 需求:把ArrayList集合中的字符串数据存储到文本文件
    *
    * 分析:
    * 通过题目的意思我们可以知道如下的一些内容,
    * ArrayList集合里存储的是字符串。
    * 遍历ArrayList集合,把数据获取到。
    * 然后存储到文本文件中。
    * 文本文件说明使用字符流。
    *
    * 数据源:
    * ArrayList<String> -- 遍历得到每一个字符串数据
    * 目的地:
    * a.txt -- FileWriter -- BufferedWriter
    */
    public class ArrayListToFileDemo {
    public static void main(String[] args) throws IOException {
    // 封装数据与(创建集合对象)
    ArrayList<String> array = new ArrayList<String>();
    array.add("hello");
    array.add("world");
    array.add("java");
     
    // 封装目的地
    BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
     
    // 遍历集合
    for (String s : array) {
    // 写数据
    bw.write(s);
    bw.newLine();
    bw.flush();
    }
     
    // 释放资源
    bw.close();
    }
    }
    ========================================
    package cn.itcast_03;
     
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
     
    /*
    * 需求:复制单极文件夹
    *
    * 数据源:e:\demo
    * 目的地:e:\test
    *
    * 分析:
    * A:封装目录
    * B:获取该目录下的所有文本的File数组
    * C:遍历该File数组,得到每一个File对象
    * D:把该File进行复制
    */
    public class CopyFolderDemo {
    public static void main(String[] args) throws IOException {
    目录 封装
    File srcFolder = new File("e:\demo");
    // 封装目的地
    File destFolder = new File("e:\test");
    // 如果目的地文件夹不存在,就创建
    if (!destFolder.exists()) {
    destFolder.mkdir();
    }
     
    // 获取该目录下的所有文本的File数组
    File[] fileArray = srcFolder.listFiles();
     
    // 遍历该File数组,得到每一个File对象
    for (File file : fileArray) {
    // System.out.println(file);
    // 数据源:e:\demo\e.mp3
    // 目的地:e:\test\e.mp3
    String name = file.getName(); // e.mp3
    File newFile = new File(destFolder, name); // e:\test\e.mp3
     
    copyFile(file, newFile);
    }
    }
     
    private static void copyFile(File file, File newFile) throws IOException {
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
    file));
    BufferedOutputStream bos = new BufferedOutputStream(
    new FileOutputStream(newFile));
     
    byte[] bys = new byte[1024];
    int len = 0;
    while ((len = bis.read(bys)) != -1) {
    bos.write(bys, 0, len);
    }
     
    bos.close();
    bis.close();
    }
    }
    ==============================================================
    package cn.itcast_04;
     
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.FilenameFilter;
    import java.io.IOException;
     
    /*
    * 需求:复制指定目录下的指定文件,并修改后缀名。
    * 指定的文件是:.java文件。
    * 指定的后缀名是:.jad
    * 指定的目录是:jad
    *
    * 数据源:e:\java\A.java
    * 目的地:e:\jad\A.jad
    *
    * 分析:
    * A:封装目录
    * B:获取该目录下的java文件的File数组
    * C:遍历该File数组,得到每一个File对象
    * D:把该File进行复制
    * E:在目的地目录下改名
    */
    public class CopyFolderDemo {
    public static void main(String[] args) throws IOException {
    // 封装目录
    File srcFolder = new File("e:\java");
    // 封装目的地
    File destFolder = new File("e:\jad");
    // 如果目的地目录不存在,就创建
    if (!destFolder.exists()) {
    destFolder.mkdir();
    }
     
    // 获取该目录下的java文件的File数组
    File[] fileArray = srcFolder.listFiles(new FilenameFilter() {
    @Override
    public boolean accept(File dir, String name) {
    return new File(dir, name).isFile() && name.endsWith(".java");
    }
    });
     
    // 遍历该File数组,得到每一个File对象
    for (File file : fileArray) {
    // System.out.println(file);
    // 数据源:e:javaDataTypeDemo.java
    // 目的地:e:\jadDataTypeDemo.java
    String name = file.getName();
    File newFile = new File(destFolder, name);
    copyFile(file, newFile);
    }
     
    // 在目的地目录下改名
    File[] destFileArray = destFolder.listFiles();
    for (File destFile : destFileArray) {
    // System.out.println(destFile);
    // e:jadDataTypeDemo.java
    // e:\jad\DataTypeDemo.jad
    String name =destFile.getName(); //DataTypeDemo.java
    String newName = name.replace(".java", ".jad");//DataTypeDemo.jad
     
    File newFile = new File(destFolder,newName);
    destFile.renameTo(newFile);
    }
    }
     
    private static void copyFile(File file, File newFile) throws IOException {
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
    file));
    BufferedOutputStream bos = new BufferedOutputStream(
    new FileOutputStream(newFile));
     
    byte[] bys = new byte[1024];
    int len = 0;
    while ((len = bis.read(bys)) != -1) {
    bos.write(bys, 0, len);
    }
     
    bos.close();
    bis.close();
    }
    }
    =================================
    package cn.itcast_05;
     
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
     
    /*
    * 需求:复制多极文件夹
    *
    * 数据源:E:JavaSEday21codedemos
    * 目的地:E:\
    *
    * 分析:
    * A:封装数据源File
    * B:封装目的地File
    * C:判断该File是文件夹还是文件
    * a:是文件夹
    * 就在目的地目录下创建该文件夹
    * 获取该File对象下的所有文件或者文件夹File对象
    * 遍历得到每一个File对象
    * 回到C
    * b:是文件
    * 就复制(字节流)
    */
    public class CopyFoldersDemo {
    public static void main(String[] args) throws IOException {
    // 封装数据源File
    File srcFile = new File("E:\JavaSE\day21\code\demos");
    // 封装目的地File
    File destFile = new File("E:\");
     
    // 复制文件夹的功能
    copyFolder(srcFile, destFile);
    }
     
    private static void copyFolder(File srcFile, File destFile)
    throws IOException {
    // 判断该File是文件夹还是文件
    if (srcFile.isDirectory()) {
    // 文件夹
    File newFolder = new File(destFile, srcFile.getName());
    newFolder.mkdir();
     
    // 获取该File对象下的所有文件或者文件夹File对象
    File[] fileArray = srcFile.listFiles();
    for (File file : fileArray) {
    copyFolder(file, newFolder);
    }
    } else {
    // 文件
    File newFile = new File(destFile, srcFile.getName());
    copyFile(srcFile, newFile);
    }
    }
     
    private static void copyFile(File srcFile, File newFile) throws IOException {
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
    srcFile));
    BufferedOutputStream bos = new BufferedOutputStream(
    new FileOutputStream(newFile));
     
    byte[] bys = new byte[1024];
    int len = 0;
    while ((len = bis.read(bys)) != -1) {
    bos.write(bys, 0, len);
    }
     
    bos.close();
    bis.close();
    }
    }
    ===============================
    package cn.itcast_06;
     
    import java.io.BufferedWriter;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.util.Comparator;
    import java.util.Scanner;
    import java.util.TreeSet;
     
    /*
    * 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低存入文本文件
    *
    * 分析:
    * A:创建学生类
    * B:创建集合对象
    * TreeSet<Student>
    * C:键盘录入学生信息存储到集合
    * D:遍历集合,把数据写到文本文件
    */
    public class StudentDemo {
    public static void main(String[] args) throws IOException {
    // 创建集合对象
    TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
    @Override
    public int compare(Student s1, Student s2) {
    int num = s2.getSum() - s1.getSum();
    int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;
    int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;
    int num4 = num3 == 0 ? s1.getEnglish() - s2.getEnglish() : num3;
    int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName())
    : num4;
    return num5;
    }
    });
     
    // 键盘录入学生信息存储到集合
    for (int x = 1; x <= 5; x++) {
    Scanner sc = new Scanner(System.in);
    System.out.println("请录入第" + x + "个的学习信息");
    System.out.println("姓名:");
    String name = sc.nextLine();
    System.out.println("语文成绩:");
    int chinese = sc.nextInt();
    System.out.println("数学成绩:");
    int math = sc.nextInt();
    System.out.println("英语成绩:");
    int english = sc.nextInt();
     
    // 创建学生对象
    Student s = new Student();
    s.setName(name);
    s.setChinese(chinese);
    s.setMath(math);
    s.setEnglish(english);
     
    // 把学生信息添加到集合
    ts.add(s);
    }
     
    // 遍历集合,把数据写到文本文件
    BufferedWriter bw = new BufferedWriter(new FileWriter("students.txt"));
    bw.write("学生信息如下:");
    bw.newLine();
    bw.flush();
    bw.write("姓名,语文成绩,数学成绩,英语成绩");
    bw.newLine();
    bw.flush();
    for (Student s : ts) {
    StringBuilder sb = new StringBuilder();
    sb.append(s.getName()).append(",").append(s.getChinese())
    .append(",").append(s.getMath()).append(",")
    .append(s.getEnglish());
    bw.write(sb.toString());
    bw.newLine();
    bw.flush();
    }
    // 释放资源
    bw.close();
    System.out.println("学习信息存储完毕");
    }
    }
     
    package cn.itcast_06;
     
    public class Student {
    // 姓名
    private String name;
    // 语文成绩
    private int chinese;
    // 数学成绩
    private int math;
    // 英语成绩
    private int english;
     
    public Student() {
    super();
    }
     
    public Student(String name, int chinese, int math, int english) {
    super();
    this.name = name;
    this.chinese = chinese;
    this.math = math;
    this.english = english;
    }
     
    public String getName() {
    return name;
    }
     
    public void setName(String name) {
    this.name = name;
    }
     
    public int getChinese() {
    return chinese;
    }
     
    public void setChinese(int chinese) {
    this.chinese = chinese;
    }
     
    public int getMath() {
    return math;
    }
     
    public void setMath(int math) {
    this.math = math;
    }
     
    public int getEnglish() {
    return english;
    }
     
    public void setEnglish(int english) {
    this.english = english;
    }
     
    public int getSum() {
    return this.chinese + this.math + this.english;
    }
    }
    ============================================================
    package cn.itcast_07;
     
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.util.Arrays;
     
    /*
    * 已知s.txt文件中有这样的一个字符串:“hcexfgijkamdnoqrzstuvwybpl”
    * 请编写程序读取数据内容,把数据排序后写入ss.txt中。
    *
    * 分析:
    * A:把s.txt这个文件给做出来
    * B:读取该文件的内容,存储到一个字符串中
    * C:把字符串转换为字符数组
    * D:对字符数组进行排序
    * E:把排序后的字符数组转换为字符串
    * F:把字符串再次写入ss.txt中
    */
    public class StringDemo {
    public static void main(String[] args) throws IOException {
    // 读取该文件的内容,存储到一个字符串中
    BufferedReader br = new BufferedReader(new FileReader("s.txt"));
    String line = br.readLine();
    br.close();
     
    // 把字符串转换为字符数组
    char[] chs = line.toCharArray();
     
    // 对字符数组进行排序
    Arrays.sort(chs);
     
    // 把排序后的字符数组转换为字符串
    String s = new String(chs);
     
    // 把字符串再次写入ss.txt中
    BufferedWriter bw = new BufferedWriter(new FileWriter("ss.txt"));
    bw.write(s);
    bw.newLine();
    bw.flush();
     
    bw.close();
    }
    }
    ===========================
    package cn.itcast_08;
     
    import java.io.FileReader;
    import java.io.IOException;
     
    /*
    * 测试MyBufferedReader的时候,你就把它当作BufferedReader一样的使用
    */
    public class MyBufferedReaderDemo {
    public static void main(String[] args) throws IOException {
    MyBufferedReader mbr = new MyBufferedReader(new FileReader("my.txt"));
     
    String line = null;
    while ((line = mbr.readLine()) != null) {
    System.out.println(line);
    }
     
    mbr.close();
     
    // System.out.println(' ' + 0); // 13
    // System.out.println(' ' + 0);// 10
    }
    }
     
     
    package cn.itcast_08;
     
    import java.io.IOException;
    import java.io.Reader;
     
    /*
    * 用Reader模拟BufferedReader的readLine()功能
    *
    * readLine():一次读取一行,根据换行符判断是否结束,只返回内容,不返回换行符
    */
    public class MyBufferedReader {
    private Reader r;
     
    public MyBufferedReader(Reader r) {
    this.r = r;
    }
     
    /*
    * 思考:写一个方法,返回值是一个字符串。
    */
    public String readLine() throws IOException {
    /*
    * 我要返回一个字符串,我该怎么办呢? 我们必须去看看r对象能够读取什么东西呢? 两个读取方法,一次读取一个字符或者一次读取一个字符数组
    * 那么,我们要返回一个字符串,用哪个方法比较好呢? 我们很容易想到字符数组比较好,但是问题来了,就是这个数组的长度是多长呢?
    * 根本就没有办法定义数组的长度,你定义多长都不合适。 所以,只能选择一次读取一个字符。
    * 但是呢,这种方式的时候,我们再读取下一个字符的时候,上一个字符就丢失了 所以,我们又应该定义一个临时存储空间把读取过的字符给存储起来。
    * 这个用谁比较和是呢?数组,集合,字符串缓冲区三个可供选择。
    * 经过简单的分析,最终选择使用字符串缓冲区对象。并且使用的是StringBuilder
    */
    StringBuilder sb = new StringBuilder();
    一个可变的字符序列。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快
     
    // 做这个读取最麻烦的是判断结束,但是在结束之前应该是一直读取,直到-1
     
     
    /*
    hello
    world
    java
     
    104101108108111
    119111114108100
    1069711897
    */
     
    int ch = 0;
    while ((ch = r.read()) != -1) { //104,101,108,108,111
    if (ch == ' ') {
    continue;
    }
     
    if (ch == ' ') {
    return sb.toString(); //hello
    } else {
    sb.append((char)ch); //hello
    }
    }
     
    // 为了防止数据丢失,判断sb的长度不能大于0
    if (sb.length() > 0) {
    return sb.toString();
    }
     
    return null;
    }
     
    /*
    * 先写一个关闭方法
    */
    public void close() throws IOException {
    this.r.close();
    }
    }
    ===============================================
    package cn.itcast_09;
     
    import java.io.FileReader;
    import java.io.IOException;
    import java.io.LineNumberReader;
     
    /*
    * BufferedReader
    * |--LineNumberReader
    * public int getLineNumber()获得当前行号。
    * public void setLineNumber(int lineNumber)
    */
    public class LineNumberReaderDemo {
    public static void main(String[] args) throws IOException {
    LineNumberReader lnr = new LineNumberReader(new FileReader("my.txt"));
     
    // 从10开始才比较好
    // lnr.setLineNumber(10);
     
    // System.out.println(lnr.getLineNumber());
    // System.out.println(lnr.getLineNumber());
    // System.out.println(lnr.getLineNumber());
     
    String line = null;
    while ((line = lnr.readLine()) != null) {
    System.out.println(lnr.getLineNumber() + ":" + line);
    }
     
    lnr.close();
    }
    }=========================================================================
     
    package cn.itcast_09;
     
    import java.io.FileReader;
    import java.io.IOException;
     
    public class MyLineNumberReaderTest {
    public static void main(String[] args) throws IOException {
    // MyLineNumberReader mlnr = new MyLineNumberReader(new FileReader(
    // "my.txt"));
     
    MyLineNumberReader2 mlnr = new MyLineNumberReader2(new FileReader(
    "my.txt"));
     
    // mlnr.setLineNumber(10);
     
    // System.out.println(mlnr.getLineNumber());
    // System.out.println(mlnr.getLineNumber());
    // System.out.println(mlnr.getLineNumber());
     
    String line = null;
    while ((line = mlnr.readLine()) != null) {
    System.out.println(mlnr.getLineNumber() + ":" + line);
    }
     
    mlnr.close();
    }
    }
     
     
    package cn.itcast_09;
     
    import java.io.IOException;
    import java.io.Reader;
     
    public class MyLineNumberReader {
    private Reader r;
    private int lineNumber = 0;
     
    public MyLineNumberReader(Reader r) {
    this.r = r;
    }
     
    public int getLineNumber() {
    // lineNumber++;
    return lineNumber;
    }
     
    public void setLineNumber(int lineNumber) {
    this.lineNumber = lineNumber;
    }
     
    public String readLine() throws IOException {
    lineNumber++;
     
    StringBuilder sb = new StringBuilder();
     
    int ch = 0;
    while ((ch = r.read()) != -1) {
    if (ch == ' ') {
    continue;
    }
     
    if (ch == ' ') {
    return sb.toString();
    } else {
    sb.append((char) ch);
    }
    }
     
    if (sb.length() > 0) {
    return sb.toString();
    }
     
    return null;
    }
     
    public void close() throws IOException {
    this.r.close();
    }
    }
     
     四.其它相关的流
    package cn.itcast_01;
     
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
     
    /*数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。
    DataInputStream 对于多线程访问不一定是安全的。 线程安全是可选的,它由此类方法的使用者负责。
    * 可以读写基本数据类型的数据
    * 数据输入流:DataInputStream
    * DataInputStream(InputStream in)
    使用指定的底层 InputStream 创建一个 DataInputStream。
    * 数据输出流:DataOutputStream
    * DataOutputStream(OutputStream out)
    */
    public class DataStreamDemo {
    public static void main(String[] args) throws IOException {
    // 写
    // write();
     
    // 读
    read();
    }
     
    private static void read() throws IOException {
    // DataInputStream(InputStream in)
    // 创建数据输入流对象
    DataInputStream dis = new DataInputStream(
    new FileInputStream("dos.txt"));
     
    // 读数据
    byte b = dis.readByte();
    short s = dis.readShort();
    int i = dis.readInt();
    long l = dis.readLong();
    float f = dis.readFloat();
    double d = dis.readDouble();
    char c = dis.readChar();
    boolean bb = dis.readBoolean();
     
    // 释放资源
    dis.close();
     
    System.out.println(b);
    System.out.println(s);
    System.out.println(i);
    System.out.println(l);
    System.out.println(f);
    System.out.println(d);
    System.out.println(c);
    System.out.println(bb);
    }
     
    private static void write() throws IOException {
    // DataOutputStream(OutputStream out)
    // 创建数据输出流对象
    DataOutputStream dos = new DataOutputStream(new FileOutputStream(
    "dos.txt"));
     
    // 写数据了
    dos.writeByte(10);
    dos.writeShort(100);
    dos.writeInt(1000);
    dos.writeLong(10000);
    dos.writeFloat(12.34F);
    dos.writeDouble(12.56);
    dos.writeChar('a');
    dos.writeBoolean(true);
     
    // 释放资源
    dos.close();
    }
    }
    ===================================================
    package cn.itcast_02;
     
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
     
    /*
    * 内存操作流:用于处理临时存储信息的,程序结束,数据就从内存中消失。
    * 字节数组:
    ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。关闭 ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException
    * ByteArrayInputStream
    * ByteArrayOutputStream
    * 字符数组:
    * CharArrayReader
    * CharArrayWriter
    * 字符串:
    * StringReader
    * StringWriter
    */
    public class ByteArrayStreamDemo {
    public static void main(String[] args) throws IOException {
    // 写数据
    // ByteArrayOutputStream()
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
     
    // 写数据
    for (int x = 0; x < 10; x++) {
    baos.write(("hello" + x).getBytes());
    }
     
    // 释放资源
    // 通过查看源码我们知道这里什么都没做,所以根本需要close()
    // baos.close();
     
    // public byte[] toByteArray()
    byte[] bys = baos.toByteArray();
     
    // 读数据
    // ByteArrayInputStream(byte[] buf)
    ByteArrayInputStream bais = new ByteArrayInputStream(bys);
     
    int by = 0;
    while ((by = bais.read()) != -1) {
    System.out.print((char) by);
    }
     
    // bais.close();
    }
    }
    ===================================================================
    package cn.itcast_03;
     
    import java.io.IOException;
    import java.io.PrintWriter;
     
    /*
    * 打印流
    * 字节流打印流 PrintStream
    PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
    * 字符打印流 PrintWriter
    * 向文本输出流打印对象的格式化表示形式。此类实现在 PrintStream 中的所有 print 方法。它不包含用于写入原始字节的方法,对于这些字节,程序应该使用未编码的字节流进行写入。
    * 打印流的特点:
    * A:只有写数据的,没有读取数据。只能操作目的地,不能操作数据源。
    * B:可以操作任意类型的数据。
    * C:如果启动了自动刷新,能够自动刷新。
    * D:该流是可以直接操作文本文件的。
    * 哪些流对象是可以直接操作文本文件的呢?
    * FileInputStream
    * FileOutputStream
    * FileReader
    * FileWriter
    * PrintStream
    * PrintWriter
    * 看API,查流对象的构造方法,如果同时有File类型和String类型的参数,一般来说就是可以直接操作文件的。
    *
    * 流:
    * 基本流:就是能够直接读写文件的
    * 高级流:在基本流基础上提供了一些其他的功能
    */
    public class PrintWriterDemo {
    public static void main(String[] args) throws IOException {
    // 作为Writer的子类使用
    PrintWriter pw = new PrintWriter("pw.txt");
     
    pw.write("hello");
    pw.write("world");
    pw.write("java");
     
    pw.close();
    }
    }
    ===============================================================================
    package cn.itcast_03;
     
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.PrintWriter;
     
    /*
    * 1:可以操作任意类型的数据。
    * print()
    * println()
    * 2:启动自动刷新
    * PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true);
    * 还是应该调用println()的方法才可以
    * 这个时候不仅仅自动刷新了,还实现了数据的换行。
    *
    * println()
    * 其实等价于于:
    * bw.write();
    * bw.newLine();
    * bw.flush();
    */
    public class PrintWriterDemo2 {
    public static void main(String[] args) throws IOException {
    // 创建打印流对象
    // PrintWriter pw = new PrintWriter("pw2.txt");
    PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true);
     
    // write()是搞不定的,怎么办呢?
    // 我们就应该看看它的新方法
    // pw.print(true);
    // pw.print(100);
    // pw.print("hello");
     
    pw.println("hello");
    pw.println(true);
    pw.println(100);
     
    pw.close();
    }
    }
     
    hello
    true
    100
    -====================================================================================
    package cn.itcast_03;
     
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.PrintWriter;
     
    /*
    * 需求:DataStreamDemo.java复制到Copy.java中
    * 数据源:
    * DataStreamDemo.java -- 读取数据 -- FileReader -- BufferedReader
    * 目的地:
    * Copy.java -- 写出数据 -- FileWriter -- BufferedWriter -- PrintWriter
    */
    public class CopyFileDemo {
    public static void main(String[] args) throws IOException {
    // 以前的版本
    // 封装数据源
    // BufferedReader br = new BufferedReader(new FileReader(
    // "DataStreamDemo.java"));
    // // 封装目的地
    // BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.java"));
    //
    // String line = null;
    // while ((line = br.readLine()) != null) {
    // bw.write(line);
    // bw.newLine();
    // bw.flush();
    // }
    //
    // bw.close();
    // br.close();
     
    // 打印流的改进版
    // 封装数据源
    BufferedReader br = new BufferedReader(new FileReader(
    "DataStreamDemo.java"));
    // 封装目的地
    PrintWriter pw = new PrintWriter(new FileWriter("Copy.java"), true);
     
    String line = null;
    while((line=br.readLine())!=null){
    pw.println(line);
    }
     
    pw.close();
    br.close();
    }
    }
    ===========================================================================
    package cn.itcast_04;
     
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
     
    /*
    * System.in 标准输入流。是从键盘获取数据的
    * System 类包含一些有用的类字段和方法。它不能被实例化。
    * 键盘录入数据:
    * A:main方法的args接收参数。
    * java HelloWorld hello world java
    * B:Scanner(JDK5以后的)
    * Scanner sc = new Scanner(System.in);
    * String s = sc.nextLine();
    * int x = sc.nextInt()
    * C:通过字符缓冲流包装标准输入流实现
    * BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    */
    public class SystemInDemo {
    public static void main(String[] args) throws IOException {
    // //获取标准输入流
    // InputStream is = System.in;
    // //我要一次获取一行行不行呢?
    // //行。
    // //怎么实现呢?
    // //要想实现,首先你得知道一次读取一行数据的方法是哪个呢?
    // //readLine()
    // //而这个方法在哪个类中呢?
    // //BufferedReader
    // //所以,你这次应该创建BufferedReader的对象,但是底层还是的使用标准输入流
    // // BufferedReader br = new BufferedReader(is);
    // //按照我们的推想,现在应该可以了,但是却报错了
    // //原因是:字符缓冲流只能针对字符流操作,而你现在是字节流,所以不能是用?
    // //那么,我还就想使用了,请大家给我一个解决方案?
    // //把字节流转换为字符流,然后在通过字符缓冲流操作
    // InputStreamReader isr = new InputStreamReader(is);
    // BufferedReader br= new BufferedReader(isr);
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
     
    System.out.println("请输入一个字符串:");
    String line = br.readLine();
    System.out.println("你输入的字符串是:" + line);
     
    System.out.println("请输入一个整数:");
    // int i = Integer.parseInt(br.readLine());
    line = br.readLine();
    int i = Integer.parseInt(line);
    System.out.println("你输入的整数是:" + i);
    }
    }
     
    =============================================
    package cn.itcast_04;
     
    import java.io.PrintStream;
     
    /*
    * 标准输入输出流
    * System类中的两个成员变量:
    * public static final InputStream in “标准”输入流。
    * public static final PrintStream out “标准”输出流。
    *
    * InputStream is = System.in;
    * PrintStream ps = System.out;
    */
    public class SystemOutDemo {
    public static void main(String[] args) {
    // 有这里的讲解我们就知道了,这个输出语句其本质是IO流操作,把数据输出到控制台。
    System.out.println("helloworld");
     
    // 获取标准输出流对象
    PrintStream ps = System.out;
    ps.println("helloworld");
     
    ps.println();
    // ps.print();//这个方法不存在
     
    // System.out.println();
    // System.out.print();
    }
    }
    =====================================================================
    package cn.itcast_04;
     
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.OutputStreamWriter;
    /*
    * 转换流的应用。
    */
    public class SystemOutDemo2 {
    public static void main(String[] args) throws IOException {
    // 获取标准输入流
    // // PrintStream ps = System.out;
    // // OutputStream os = ps;
    // OutputStream os = System.out; // 多态
    // // 我能不能按照刚才使用标准输入流的方式一样把数据输出到控制台呢?
    // OutputStreamWriter osw = new OutputStreamWriter(os);
    // BufferedWriter bw = new BufferedWriter(osw);
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
    System.out));
     
    bw.write("hello");
    bw.newLine();
    // bw.flush();
    bw.write("world");
    bw.newLine();
    // bw.flush();
    bw.write("java");
    bw.newLine();
    bw.flush();
     
    bw.close();
    }
    }
     
    =======================================
    package cn.itcast_05;
     
    import java.io.IOException;
    import java.io.RandomAccessFile;
     
    /*
    * 随机访问流:
    * RandomAccessFile类不属于流,是Object类的子类。
    * 但它融合了InputStream和OutputStream的功能。
    * 支持对文件的随机访问读取和写入。
    * 实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过 getFilePointer 方法读取,并通过 seek 方法设置。
    * public RandomAccessFile(String name,String mode):第一个参数是文件路径,第二个参数是操作文件的模式。
    * 模式有四种,我们最常用的一种叫"rw",这种方式表示我既可以写数据,也可以读取数据
    */
    public class RandomAccessFileDemo {
    public static void main(String[] args) throws IOException {
    // write();
    read();
    }
     
    private static void read() throws IOException {
    // 创建随机访问流对象
    RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw");
     
    int i = raf.readInt();
    System.out.println(i);
    // 该文件指针可以通过 getFilePointer方法读取,并通过 seek 方法设置。
    System.out.println("当前文件的指针位置是:" + raf.getFilePointer());
     
    char ch = raf.readChar();
    System.out.println(ch);
    System.out.println("当前文件的指针位置是:" + raf.getFilePointer());
     
    String s = raf.readUTF();
    System.out.println(s);
    System.out.println("当前文件的指针位置是:" + raf.getFilePointer());
     
    // 我不想重头开始了,我就要读取a,怎么办呢?
    raf.seek(4);
    ch = raf.readChar();
    System.out.println(ch);
    }
     
    private static void write() throws IOException {
    // 创建随机访问流对象
    RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw");
     
    // 怎么玩呢?
    raf.writeInt(100);
    raf.writeChar('a');
    raf.writeUTF("中国");
     
    raf.close();
    }
    }
    ======================================
    package cn.itcast_06;
     
    import java.io.BufferedOutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.SequenceInputStream;
     
    /*
    * 以前的操作:
    * a.txt -- b.txt
    * c.txt -- d.txt
    *
    * 现在想要:
    * a.txt+b.txt -- c.txt
    */
    public class SequenceInputStreamDemo {
    public static void main(String[] args) throws IOException {
    // SequenceInputStream(InputStream s1, InputStream s2)
    // 需求:把ByteArrayStreamDemo.java和DataStreamDemo.java的内容复制到Copy.java中
    InputStream s1 = new FileInputStream("ByteArrayStreamDemo.java");
    InputStream s2 = new FileInputStream("DataStreamDemo.java");
    SequenceInputStream sis = new SequenceInputStream(s1, s2);
    BufferedOutputStream bos = new BufferedOutputStream(
    new FileOutputStream("Copy.java"));
     
    // 如何写读写呢,其实很简单,你就按照以前怎么读写,现在还是怎么读写
    byte[] bys = new byte[1024];
    int len = 0;
    while ((len = sis.read(bys)) != -1) {
    bos.write(bys, 0, len);
    }
     
    bos.close();
    sis.close();
    }
    }
    ====================================================================
    package cn.itcast_06;
     
    import java.io.BufferedOutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.SequenceInputStream;
    import java.util.Enumeration;
    import java.util.Vector;
     
    /*
    * 以前的操作:
    * a.txt -- b.txt
    * c.txt -- d.txt
    * e.txt -- f.txt
    *
    * 现在想要:
    * a.txt+b.txt+c.txt -- d.txt
    */
    public class SequenceInputStreamDemo2 {
    public static void main(String[] args) throws IOException {
    // 需求:把下面的三个文件的内容复制到Copy.java中
    // ByteArrayStreamDemo.java,CopyFileDemo.java,DataStreamDemo.java
     
    // SequenceInputStream(Enumeration e)
    // 通过简单的回顾我们知道了Enumeration是Vector中的一个方法的返回值类型。
    // Enumeration<E> elements()
    Vector<InputStream> v = new Vector<InputStream>();
    InputStream s1 = new FileInputStream("ByteArrayStreamDemo.java");
    InputStream s2 = new FileInputStream("CopyFileDemo.java");
    InputStream s3 = new FileInputStream("DataStreamDemo.java");
    v.add(s1);
    v.add(s2);
    v.add(s3);
    Enumeration<InputStream> en = v.elements();
    SequenceInputStream sis = new SequenceInputStream(en);
    BufferedOutputStream bos = new BufferedOutputStream(
    new FileOutputStream("Copy.java"));
     
    // 如何写读写呢,其实很简单,你就按照以前怎么读写,现在还是怎么读写
    byte[] bys = new byte[1024];
    int len = 0;
    while ((len = sis.read(bys)) != -1) {
    bos.write(bys, 0, len);
    }
     
    bos.close();
    sis.close();
    }
    }
     
    ==================================================================
    package cn.itcast_07;
     
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
     
    /*
    * 序列化流:把对象按照流一样的方式存入文本文件或者在网络中传输。对象 -- 流数据(ObjectOutputStream)
    * 反序列化流:把文本文件中的流对象数据或者网络中的流对象数据还原成对象。流数据 -- 对象(ObjectInputStream)
    */
    public class ObjectStreamDemo {
    public static void main(String[] args) throws IOException,
    ClassNotFoundException {
    // 由于我们要对对象进行序 列化,所以我们先自定义一个类
    // 序列化数据其实就是把对象写到文本文件
    // write();
     
    read();
    }
     
    private static void read() throws IOException, ClassNotFoundException {
    // 创建反序列化对象
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
    "oos.txt"));
     
    // 还原对象
    Object obj = ois.readObject();
     
    // 释放资源
    ois.close();
     
    // 输出对象
    System.out.println(obj);
    }
     
    private static void write() throws IOException {
    // 创建序列化流对象
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
    "oos.txt"));
     
    // 创建对象
    Person p = new Person("林青霞", 27);
     
    // public final void writeObject(Object obj)
    oos.writeObject(p);
     
    // 释放资源
    oos.close();
    }
    }
     
    ============================================================
    package cn.itcast_07;
     
    import java.io.Serializable;
     
    /*
    * NotSerializableException:未序列化异常
    * 当实例需要具有序列化接口时,抛出此异常。序列化运行时或实例的类会抛出此异常。参数应该为类的名称
    * 类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
    * 该接口居然没有任何方法,类似于这种没有方法的接口被称为标记接口。
    *
    * java.io.InvalidClassException:
    * cn.itcast_07.Person; local class incompatible:
    * stream classdesc serialVersionUID = -2071565876962058344,
    * local class serialVersionUID = -8345153069362641443
    * 序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为 "serialVersionUID" 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID:
    ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
    如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java(TM) 对象序列化规范”中所述。不过,强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修饰符显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于直接声明类 -- serialVersionUID 字段作为继承成员没有用处。数组类不能声明一个明确的 serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配 serialVersionUID 值的要求。
    * 为什么会有问题呢?
    * Person类实现了序列化接口,那么它本身也应该有一个标记值。
    * 这个标记值假设是100。
    * 开始的时候:
    * Person.class -- id=100
    * wirte数据: oos.txt -- id=100
    * read数据: oos.txt -- id=100
    *
    * 现在:
    * Person.class -- id=200
    * wirte数据: oos.txt -- id=100
    * read数据: oos.txt -- id=100
    * 我们在实际开发中,可能还需要使用以前写过的数据,不能重新写入。怎么办呢?
    * 回想一下原因是因为它们的id值不匹配。
    * 每次修改java文件的内容的时候,class文件的id值都会发生改变。
    * 而读取文件的时候,会和class文件中的id值进行匹配。所以,就会出问题。
    * 但是呢,如果我有办法,让这个id值在java文件中是一个固定的值,这样,你修改文件的时候,这个id值还会发生改变吗?
    * 不会。现在的关键是我如何能够知道这个id值如何表示的呢?
    * 不用担心,你不用记住,也没关系,点击鼠标即可。
    * 你难道没有看到黄色警告线吗?
    *
    * 我们要知道的是:
    * 看到类实现了序列化接口的时候,要想解决黄色警告线问题,就可以自动产生一个序列化id值。
    * 而且产生这个值以后,我们对类进行任何改动,它读取以前的数据是没有问题的。
    *
    * 注意:
    * 我一个类中可能有很多的成员变量,有些我不想进行序列化。请问该怎么办呢?
    * 使用transient关键字声明不需要序列化的成员变量
    */
    public class Person implements Serializable {
    private static final long serialVersionUID = -2071565876962058344L;
     
    private String name;
     
    // private int age;
     
    private transient int age;
     
    // int age;
     
    public Person() {
    super();
    }
     
    public Person(String name, int age) {
    super();
    this.name = name;
    this.age = age;
    }
     
    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;
    }
     
    @Override
    public String toString() {
    return "Person [name=" + name + ", age=" + age + "]";
    }
    }
    ======================================================
    package cn.itcast_08;
     
    import java.util.Properties;
    import java.util.Set;
     
    /*
    * Properties:属性集合类。是一个可以和IO流相结合使用的集合类。
    * Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
    *
    * 是Hashtable的子类,说明是一个Map集合。
    */
    public class PropertiesDemo {
    public static void main(String[] args) {
    // 作为Map集合的使用
    // 下面这种用法是错误的,一定要看API,如果没有<>,就说明该类不是一个泛型类,在使用的时候就不能加泛型
    // Properties<String, String> prop = new Properties<String, String>();
     
    Properties prop = new Properties();
     
    // 添加元素
    prop.put("it002", "hello");
    prop.put("it001", "world");
    prop.put("it003", "java");
     
    // System.out.println("prop:" + prop);
     
    // 遍历集合
    Set<Object> set = prop.keySet();
    for (Object key : set) {
    Object value = prop.get(key);
    System.out.println(key + "---" + value);
    }
    }
    }
    =============================================================================================package cn.itcast_08;
     
    import java.util.Properties;
    import java.util.Set;
     
    /*
    * 特殊功能:
    * public Object setProperty(String key,String value):添加元素
    * public String getProperty(String key):获取元素
    * public Set<String> stringPropertyNames():获取所有的键的集合
    */
    public class PropertiesDemo2 {
    public static void main(String[] args) {
    // 创建集合对象
    Properties prop = new Properties();
     
    // 添加元素
    prop.setProperty("张三", "30");
    prop.setProperty("李四", "40");
    prop.setProperty("王五", "50");
     
    // public Set<String> stringPropertyNames():获取所有的键的集合
    Set<String> set = prop.stringPropertyNames();
    for (String key : set) {
    String value = prop.getProperty(key);
    System.out.println(key + "---" + value);
    }
    }
    }
     
    /*
    * class Hashtalbe<K,V> { public V put(K key,V value) { ... } }
    *
    * class Properties extends Hashtable { public V setProperty(String key,String
    * value) { return put(key,value); } }
    */
    =====================================================================
    package cn.itcast_08;
     
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.Reader;
    import java.io.Writer;
    import java.util.Properties;
     
    /*
    * 这里的集合必须是Properties集合:
    * public void load(Reader reader):把文件中的数据读取到集合中
    * public void store(Writer writer,String comments):把集合中的数据存储到文件
    *
    * 单机版游戏:
    * 进度保存和加载。
    * 三国群英传,三国志,仙剑奇侠传...
    *
    * 吕布=1
    * 方天画戟=1
    */
    public class PropertiesDemo3 {
    public static void main(String[] args) throws IOException {
    // myLoad();
     
    myStore();
    }
     
    private static void myStore() throws IOException {
    // 创建集合对象
    Properties prop = new Properties();
     
    prop.setProperty("林青霞", "27");
    prop.setProperty("武鑫", "30");
    prop.setProperty("刘晓曲", "18");
     
    //public void store(Writer writer,String comments):把集合中的数据存储到文件
    Writer w = new FileWriter("name.txt");
    prop.store(w, "helloworld");
    w.close();
    }
     
    private static void myLoad() throws IOException {
    Properties prop = new Properties();
     
    // public void load(Reader reader):把文件中的数据读取到集合中
    // 注意:这个文件的数据必须是键值对形式
    Reader r = new FileReader("prop.txt");
    prop.load(r);
    r.close();
     
    System.out.println("prop:" + prop);
    }
    }
     
    ============================================================================
    package cn.itcast_08;
     
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.Reader;
    import java.io.Writer;
    import java.util.Properties;
    import java.util.Set;
     
    /*
    * 我有一个文本文件(user.txt),我知道数据是键值对形式的,但是不知道内容是什么。
    * 请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其实为”100”
    *
    * 分析:
    * A:把文件中的数据加载到集合中
    * B:遍历集合,获取得到每一个键
    * C:判断键是否有为"lisi"的,如果有就修改其值为"100"
    * D:把集合中的数据重新存储到文件中
    */
    public class PropertiesTest {
    public static void main(String[] args) throws IOException {
    // 把文件中的数据加载到集合中
    Properties prop = new Properties();
    Reader r = new FileReader("user.txt");
    prop.load(r);
    r.close();
     
    // 遍历集合,获取得到每一个键
    Set<String> set = prop.stringPropertyNames();
    for (String key : set) {
    // 判断键是否有为"lisi"的,如果有就修改其值为"100"
    if ("lisi".equals(key)) {
    prop.setProperty(key, "100");
    break;
    }
    }
     
    // 把集合中的数据重新存储到文件中
    Writer w = new FileWriter("user.txt");
    prop.store(w, null);
    w.close();
    }
    }
    ==========================================================================================
    package cn.itcast_08;
     
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.Reader;
    import java.io.Writer;
    import java.util.Properties;
     
    /*
    * 我有一个猜数字小游戏的程序,请写一个程序实现在测试类中只能用5次,超过5次提示:游戏试玩已结束,请付费。
    */
    public class PropertiesTest2 {
    public static void main(String[] args) throws IOException {
    // 读取某个地方的数据,如果次数不大于5,可以继续玩。否则就提示"游戏试玩已结束,请付费。"
    // 创建一个文件
    // File file = new File("count.txt");
    // if (!file.exists()) {
    // file.createNewFile();
    // }
     
    // 把数据加载到集合中
    Properties prop = new Properties();
    Reader r = new FileReader("count.txt");
    prop.load(r);
    r.close();
     
    // 我自己的程序,我当然知道里面的键是谁
    String value = prop.getProperty("count");
    int number = Integer.parseInt(value);
     
    if (number > 5) {
    System.out.println("游戏试玩已结束,请付费。");
    System.exit(0);
    } else {
    number++;
    prop.setProperty("count", String.valueOf(number));
    Writer w = new FileWriter("count.txt");
    prop.store(w, null);
    w.close();
     
    GuessNumber.start();
    }
    }
    }
    ===================================================================================
    package cn.itcast_09;
     
    import java.io.IOException;
    import java.nio.charset.Charset;
    import java.nio.file.Files;
    import java.nio.file.Paths;
    import java.util.ArrayList;
     
    /*
    * nio包在JDK4出现,提供了IO流的操作效率。但是目前还不是大范围的使用。
    * 有空的话了解下,有问题再问我。
    *
    * JDK7的之后的nio:
    * Path:路径
    * Paths:有一个静态方法返回一个路径
    * public static Path get(URI uri)
    * Files:提供了静态方法供我们使用
    * public static long copy(Path source,OutputStream out):复制文件
    * public static Path write(Path path,Iterable<? extends CharSequence> lines,Charset cs,OpenOption... options)
    */
    public class NIODemo {
    public static void main(String[] args) throws IOException {
    // public static long copy(Path source,OutputStream out)
    // Files.copy(Paths.get("ByteArrayStreamDemo.java"), new
    // FileOutputStream(
    // "Copy.java"));
     
    ArrayList<String> array = new ArrayList<String>();
    array.add("hello");
    array.add("world");
    array.add("java");
    Files.write(Paths.get("array.txt"), array, Charset.forName("GBK"));
    }
    }
    ==================================================================
     
    package cn.itcast.dao;
     
    import cn.itcast.pojo.User;
     
    /**
    * 这是针对用户进行操作的接口
    *
    * @author 风清扬
    * @version V1.1
    *
    */
    public interface UserDao {
    /**
    * 这是用户登录功能
    *
    * @param username
    * 用户名
    * @param password
    * 密码
    * @return 返回登录是否成功
    */
    public abstract boolean isLogin(String username, String password);
     
    /**
    * 这是用户注册功能
    *
    * @param user
    * 要注册的用户信息
    */
    public abstract void regist(User user);
    }
     
     
     
     
    package cn.itcast.dao.impl;
     
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
     
    import cn.itcast.dao.UserDao;
    import cn.itcast.pojo.User;
     
    /**
    * 这是用户操作的具体实现类(IO版)
    *
    * @author 风清扬
    * @version V1.1
    *
    */
    public class UserDaoImpl implements UserDao {
    // 为了保证文件一加载就创建
    private static File file = new File("user.txt");
     
    static {
    try {
    file.createNewFile();
    } catch (IOException e) {
    System.out.println("创建文件失败");
    // e.printStackTrace();
    }
    }
     
    @Override
    public boolean isLogin(String username, String password) {
    boolean flag = false;
     
    BufferedReader br = null;
    try {
    // br = new BufferedReader(new FileReader("user.txt"));
    br = new BufferedReader(new FileReader(file));
    String line = null;
    while ((line = br.readLine()) != null) {
    // 用户名=密码
    String[] datas = line.split("=");
    if (datas[0].equals(username) && datas[1].equals(password)) {
    flag = true;
    break;
    }
    }
    } catch (FileNotFoundException e) {
    System.out.println("用户登录找不到信息所在的文件");
    // e.printStackTrace();
    } catch (IOException e) {
    System.out.println("用户登录失败");
    // e.printStackTrace();
    } finally {
    if (br != null) {
    try {
    br.close();
    } catch (IOException e) {
    System.out.println("用户登录释放资源失败");
    // e.printStackTrace();
    }
    }
    }
     
    return flag;
    }
     
    @Override
    public void regist(User user) {
    /*
    * 为了让注册的数据能够有一定的规则,我就自己定义了一个规则: 用户名=密码
    */
    BufferedWriter bw = null;
    try {
    // bw = new BufferedWriter(new FileWriter("user.txt"));
    // bw = new BufferedWriter(new FileWriter(file));
    // 为了保证数据是追加写入,必须加true
    bw = new BufferedWriter(new FileWriter(file, true));
    bw.write(user.getUsername() + "=" + user.getPassword());
    bw.newLine();
    bw.flush();
    } catch (IOException e) {
    System.out.println("用户注册失败");
    // e.printStackTrace();
    } finally {
    if (bw != null) {
    try {
    bw.close();
    } catch (IOException e) {
    System.out.println("用户注册释放资源失败");
    // e.printStackTrace();
    }
    }
    }
    }
    }
     
     
    package cn.itcast.game;
     
    import java.util.Scanner;
     
    /**
    * 这是猜数字小游戏
    *
    * @author 风清扬
    * @version V1.1
    *
    */
    public class GuessNumber {
    private GuessNumber() {
    }
     
    public static void start() {
    // 产生一个随机数
    int number = (int) (Math.random() * 100) + 1;
     
    // 定义一个统计变量
    int count = 0;
     
    while (true) {
    // 键盘录入一个数据
    Scanner sc = new Scanner(System.in);
    System.out.println("请输入数据(1-100):");
    int guessNumber = sc.nextInt();
     
    count++;
     
    // 判断
    if (guessNumber > number) {
    System.out.println("你猜的数据" + guessNumber + "大了");
    } else if (guessNumber < number) {
    System.out.println("你猜的数据" + guessNumber + "小了");
    } else {
    System.out.println("恭喜你," + count + "次就猜中了");
    break;
    }
    }
    }
    }
     
    package cn.itcast.pojo;
     
    /**
    * 这是用户基本描述类
    *
    * @author 风清扬
    * @version V1.1
    *
    */
    public class User {
    // 用户名
    private String username;
    // 密码
    private String password;
     
    public User() {
    }
     
    public String getUsername() {
    return username;
    }
     
    public void setUsername(String username) {
    this.username = username;
    }
     
    public String getPassword() {
    return password;
    }
     
    public void setPassword(String password) {
    this.password = password;
    }
    }
     
    package cn.itcast.test;
     
    import java.util.Scanner;
     
    import cn.itcast.dao.UserDao;
    import cn.itcast.dao.impl.UserDaoImpl;
    import cn.itcast.game.GuessNumber;
    import cn.itcast.pojo.User;
     
    /**
    * 用户测试类
    *
    * @author 风清扬
    * @version V1.1
    *
    */
    public class UserTest {
    public static void main(String[] args) {
    // 为了能够回来
    while (true) {
    // 欢迎界面,给出选择项
    System.out.println("--------------欢迎光临--------------");
    System.out.println("1 登录");
    System.out.println("2 注册");
    System.out.println("3 退出");
    System.out.println("请输入你的选择:");
    // 键盘录入选择,根据选择做不同的操作
    Scanner sc = new Scanner(System.in);
    // 为了后面的录入信息的方便,我所有的数据录入全部用字符接收
    String choiceString = sc.nextLine();
     
    // switch语句的多个地方要使用,我就定义到外面
    UserDao ud = new UserDaoImpl();
     
    // 经过简单的思考,我选择了switch
    switch (choiceString) {
    case "1":
    // 登录界面,请输入用户名和密码
    System.out.println("--------------登录界面--------------");
    System.out.println("请输入用户名:");
    String username = sc.nextLine();
    System.out.println("请输入密码:");
    String password = sc.nextLine();
     
    // 调用登录功能
    // UserDao ud = new UserDaomImpl();
     
    boolean flag = ud.isLogin(username, password);
    if (flag) {
    System.out.println("登录成功,可以开始玩游戏了");
     
    System.out.println("你玩吗?y/n");
    while (true) {
    String resultString = sc.nextLine();
    if (resultString.equalsIgnoreCase("y")) {
    // 玩游戏
    GuessNumber.start();
    System.out.println("你还玩吗?y/n");
    } else {
    break;
    }
    }
    System.out.println("谢谢使用,欢迎下次再来");
    System.exit(0);
    // break; //这里写break,结束的是switch
    } else {
    System.out.println("用户名或者密码有误,登录失败");
    }
    break;
    case "2":
    // 欢迎界面,请输入用户名和密码
    System.out.println("--------------注册界面--------------");
    System.out.println("请输入用户名:");
    String newUsername = sc.nextLine();
    System.out.println("请输入密码:");
    String newPassword = sc.nextLine();
     
    // 把用户名和密码封装到一个对象中
    User user = new User();
    user.setUsername(newUsername);
    user.setPassword(newPassword);
     
    // 调用注册功能
    // 多态
    // UserDao ud = new UserDaoImpl();
    // 具体类使用
    // UserDaoImpl udi = new UserDaoImpl();
     
    ud.regist(user);
    System.out.println("注册成功");
    break;
    case "3":
    default:
    System.out.println("谢谢使用,欢迎下次再来");
    System.exit(0);
    break;
    }
    }
    }
    }
    ===================================================================================================
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    JAVA中变量的类型及命名规范
    JAVA、JDK等入门概念,下载安装JAVA并配置环境变量
    大家好,我是一个JAVA初学者,想在这里记下自己学习过程中的点点滴滴,请多多关照
    多线程并发问题解决之redis锁
    设计模式之动态代理
    设计模式之静态代理
    spring之IOC模拟实现
    spring boot+kafka整合
    metrics+spring+influxdb整合
    MongoError: no primary found in replicaset
  • 原文地址:https://www.cnblogs.com/yejibigdata/p/7835303.html
Copyright © 2020-2023  润新知