JAVA IO流(韩顺平)

目录

一、文件

1.1 什么是文件

1.2 文件流

二、常用的文件操作

2.1 创建文件对象相关构造器和方法

2.1.1 代码实现

2.2 获取文件的相关信息

2.2.1 代码实现

2.2.2 相对路径和绝对路径

2.3 目录的操作和文件删除

三、IO 流原理及流的分类

3.1 Java IO 流原理

3.2 流的分类

四、IO 流体系图-常用的类

 4.1 FileInputStream (字节输入流)

4.1.1 FileInputStream应用实例

4.2 FileOutputStream(字节输出流)

4.2.1 FileOutputStream应用实例1

 4.2.2 FileOutputStream应用实例2

4.3 FileReader和FileWriter(字符输入流)

4.3.1FileReader 相关方法

4.3.2 FileWriter 常用方法

4.3.1 FileReader 和 FileWriter 应用案例

五、节点流和处理流

5.1 节点流和处理流基本介绍

 5.2 节点流和处理流的区别和联系

5.3 处理流主要功能

5.4 处理流-BufferedReader 和 BufferedWriter

5.4.1 案例1:BufferedReader读取文本文件

5.4.2 案例2:BufferedWriter写入文本文件

5.4.3 使用BufferedWriter和BufferedReader进行文件拷贝

5.5 处理流-BufferedInputStream 和 BufferedOutputStream

5.5.1 BufferedInputStream和BufferedOutputStream应用实例

5.6 对象流-ObjectInputStream 和 ObjectOutputStream(仍是个处理流)

5.6.1 案例引出

5.6.2 序列化和反序列化

5.6.3 对象流介绍

5.6.4 transient关键词

5.6.5 使用ObjectOutputStream进行序列化

5.6.6 使用ObjectInputStream进行反序列化

5.6.7 注意事项和细节说明

5.7 标准输入流与输出流

5.7.1 基本介绍

 5.7.2 乱码引出转换流

5.7.3 转换流-InputStreamReader和OutputStreamWriter

5.7.4 应用案例:使用 InputStreamReader 转换流解决中文乱码问题

5.7.5 案例2: 把FileOutputStream 字节流,转成字符流 OutputStreamWriter

六、打印流

6.1 PrintStream

6.2 PrintWriter

七、Propertise 类

7.1 基本介绍

7.2 利用传统方法解决应用实例

7.3 Properties类的方法 

 7.3.1 使用Properties类完成对mysql.properties的读取

7.3.2 使用Properties类添加key-val到新文件mysql2.properties中

 7.3.3 使用Properties类完成对mysql.properties的读取,并修改某个key-val


一、文件

1.1 什么是文件

文件是保存数据的地方

1.2 文件流

文件在程序中是以流的形式来操作的

流:数据在数据源(文件)和程序(内存)之间经历的路径;

输入流:数据从数据源(文件)到程序(内存)的路径;

输出流:数据从程序(内存)到数据源(文件)的路径。

二、常用的文件操作

2.1 创建文件对象相关构造器和方法

2.1.1 代码实现

public class FileCreate {
    public static void main(String[] args) {

    }

    //方式1 new File(String pathname)
    @Test
    public void create01() {
        String filePath = "e:\\news1.txt";
        File file = new File(filePath);

        try {
            file.createNewFile();
            System.out.println("文件创建成功");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    //方式2 new File(File parent,String child) //根据父目录文件+子路径构建
    //e:\\news2.txt
    @Test
    public  void create02() {
        File parentFile = new File("e:\\");
        String fileName = "news2.txt";
        //这里的file对象,在java程序中,只是一个对象
        //只有执行了createNewFile 方法,才会真正的,在磁盘创建该文件
        File file = new File(parentFile, fileName);

        try {
            file.createNewFile();
            System.out.println("创建成功~");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //方式3 new File(String parent,String child) //根据父目录+子路径构建
    @Test
    public void create03() {
        //String parentPath = "e:\\";
        String parentPath = "e:\\";
        String fileName = "news4.txt";
        File file = new File(parentPath, fileName);

        try {
            file.createNewFile();
            System.out.println("创建成功~");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //下面四个都是抽象类
    //
    //InputStream
    //OutputStream
    //Reader //字符输入流
    //Writer  //字符输出流
}

2.2 获取文件的相关信息

一般有getName,getAbsolutePath,getParent,length,exists,isFile,ifDirectory

2.2.1 代码实现

//获取文件的信息
    @Test
    public void info() {
        //先创建文件对象
        File file = new File("e:\\news1.txt");

        //调用相应的方法,得到对应信息
        System.out.println("文件名字=" + file.getName());
        //getName、getAbsolutePath、getParent、length、exists、isFile、isDirectory
        System.out.println("文件绝对路径=" + file.getAbsolutePath());
        System.out.println("文件父级目录=" + file.getParent());
        System.out.println("文件大小(字节)=" + file.length());
        System.out.println("文件是否存在=" + file.exists());//T
        System.out.println("是不是一个文件=" + file.isFile());//T
        System.out.println("是不是一个目录=" + file.isDirectory());//F

2.2.2 相对路径和绝对路径

相对路径:从当前目录开始定位,形成一个路径

绝对路径:从顶级目录开始地位形成的路径

2.3 目录的操作和文件删除

mkdir创建一级目录,mkdirs创建多级目录,delet删除空目录或文件

@Test
    public void m1() {

        String filePath = "e:\\news1.txt";
        File file = new File(filePath);
        if (file.exists()) {
            if (file.delete()) {
                System.out.println(filePath + "删除成功");
            } else {
                System.out.println(filePath + "删除失败");
            }
        } else {
            System.out.println("该文件不存在...");
        }

    }

    //判断 D:\\demo02 是否存在,存在就删除,否则提示不存在
    //这里我们需要体会到,在java编程中,目录也被当做文件
    @Test
    public void m2() {

        String filePath = "D:\\demo02";
        File file = new File(filePath);
        if (file.exists()) {
            if (file.delete()) {
                System.out.println(filePath + "删除成功");
            } else {
                System.out.println(filePath + "删除失败");
            }
        } else {
            System.out.println("该目录不存在...");
        }

    }

    //判断 D:\\demo\\a\\b\\c 目录是否存在,如果存在就提示已经存在,否则就创建
    @Test
    public void m3() {

        String directoryPath = "D:\\demo\\a\\b\\c";
        File file = new File(directoryPath);
        if (file.exists()) {
            System.out.println(directoryPath + "存在..");
        } else {
            if (file.mkdirs()) { //创建一级目录使用mkdir() ,创建多级目录使用mkdirs()
                System.out.println(directoryPath + "创建成功..");
            } else {
                System.out.println(directoryPath + "创建失败...");
            }
        }
    }

三、IO 流原理及流的分类

3.1 Java IO 流原理

1. I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理数据传输。如读/写文件,网络通讯等。

2. Java程序中,对于数据的输入/输出操作以"流(stream)"的方式进行。

3. ava.io包下提供了各种"流"类和接口,用以获取不同种类的数据,并通过方法输入或输出数据

4. 输入input:读取外部数据(磁盘,光盘等存储设备的数据)到程序(内存)中。

5. 输出output:将程序(内存)数据输出到磁盘,光盘等存储设备中

3.2 流的分类

1. 按操作数据单位不同分为:字节流(8 bit),字符流(按字符)

2. 按数据流的流向不同分为:输入流,输出流

3. 按流的角色的不同分为:节点流,处理流/包装流

1)java中IO流共涉及40多个类,实际上非常规则,都是从如上4个抽象基类派生的。

2)由这4个类派生出来的子类名称都是以其父类名为子类名后缀

四、IO 流体系图-常用的类

IO 流体系图

 4.1 FileInputStream (字节输入流)

1. InputStream抽象类是所有类字节输入流的超类

2. InputStream常用的子类:

        1)FileInputStream:文件输入流

        2)BufferedInputStream:缓存字节输入流

        3)ObjectInputStream:对象字节输入流

4.1.1 FileInputStream应用实例

@Test
    public void readFile01() {
        String filePath = "e:\\hello.txt";
        int readData = 0;
        FileInputStream fileInputStream = null;
        try {
            //创建 FileInputStream 对象,用于读取 文件
            fileInputStream = new FileInputStream(filePath);
            //从该输入流读取一个字节的数据。 如果没有输入可用,此方法将阻止。
            //如果返回-1 , 表示读取完毕
            while ((readData = fileInputStream.read()) != -1) {
                System.out.print((char)readData);//转成char显示
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭文件流,释放资源.
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 使用 read(byte[] b) 读取文件,提高效率
     */
    @Test
    public void readFile02() {
        String filePath = "e:\\hello.txt";
        //字节数组
        byte[] buf = new byte[8]; //一次读取8个字节.
        int readLen = 0;
        FileInputStream fileInputStream = null;
        try {
            //创建 FileInputStream 对象,用于读取 文件
            fileInputStream = new FileInputStream(filePath);
            //从该输入流读取最多b.length字节的数据到字节数组。 此方法将阻塞,直到某些输入可用。
            //如果返回-1 , 表示读取完毕
            //如果读取正常, 返回实际读取的字节数
            while ((readLen = fileInputStream.read(buf)) != -1) {
                System.out.print(new String(buf, 0, readLen));//显示
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭文件流,释放资源.
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

4.2 FileOutputStream(字节输出流)

4.2.1 FileOutputStream应用实例1

 @Test
    public void writeFile() {

        //创建 FileOutputStream对象
        String filePath = "e:\\a.txt";
        FileOutputStream fileOutputStream = null;
        try {
            //得到 FileOutputStream对象 对象
            //老师说明
            //1. new FileOutputStream(filePath) 创建方式,当写入内容是,会覆盖原来的内容
            //2. new FileOutputStream(filePath, true) 创建方式,当写入内容是,是追加到文件后面
            fileOutputStream = new FileOutputStream(filePath, true);
            //写入一个字节
            //fileOutputStream.write('H');//
            //写入字符串
            String str = "hsp,world!";
            //str.getBytes() 可以把 字符串-> 字节数组
            //fileOutputStream.write(str.getBytes());
            /*
            write(byte[] b, int off, int len) 将 len字节从位于偏移量 off的指定字节数组写入此文件输出流
             */
            fileOutputStream.write(str.getBytes(), 0, 3);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

 4.2.2 FileOutputStream应用实例2

要求:编程完成图片/音乐 的拷贝

public class FileCopy {
    public static void main(String[] args) {
        //完成 文件拷贝,将 e:\\Koala.jpg 拷贝 c:\\
        //思路分析
        //1. 创建文件的输入流 , 将文件读入到程序
        //2. 创建文件的输出流, 将读取到的文件数据,写入到指定的文件.
        String srcFilePath = "e:\\Koala.jpg";
        String destFilePath = "e:\\Koala3.jpg";
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;

        try {

            fileInputStream = new FileInputStream(srcFilePath);
            fileOutputStream = new FileOutputStream(destFilePath);
            //定义一个字节数组,提高读取效果
            byte[] buf = new byte[1024];
            int readLen = 0;
            while ((readLen = fileInputStream.read(buf)) != -1) {
                //读取到后,就写入到文件 通过 fileOutputStream
                //即,是一边读,一边写
                fileOutputStream.write(buf, 0, readLen);//一定要使用这个方法

            }
            System.out.println("拷贝ok~");


        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                //关闭输入流和输出流,释放资源
                if (fileInputStream != null) {
                    fileInputStream.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }
}

4.3 FileReader和FileWriter(字符输入流)

4.3.1FileReader 相关方法

4.3.2 FileWriter 常用方法

4.3.1 FileReader 和 FileWriter 应用案例

要求:1)使用 FileReader 从 story.txt 读取内容,并显示

 /**
     * 单个字符读取文件
     */
    @Test
    public void readFile01() {
        String filePath = "e:\\story.txt";
        FileReader fileReader = null;
        int data = 0;
        //1. 创建FileReader对象
        try {
            fileReader = new FileReader(filePath);
            //循环读取 使用read, 单个字符读取
            while ((data = fileReader.read()) != -1) {
                System.out.print((char) data);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fileReader != null) {
                    fileReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 字符数组读取文件
     */
    @Test
    public void readFile02() {
        System.out.println("~~~readFile02 ~~~");
        String filePath = "e:\\story.txt";
        FileReader fileReader = null;

        int readLen = 0;
        char[] buf = new char[8];
        //1. 创建FileReader对象
        try {
            fileReader = new FileReader(filePath);
            //循环读取 使用read(buf), 返回的是实际读取到的字符数
            //如果返回-1, 说明到文件结束
            while ((readLen = fileReader.read(buf)) != -1) {
                System.out.print(new String(buf, 0, readLen));
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fileReader != null) {
                    fileReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

2) 使用 FileWriter 将 “风雨之后,定见彩虹” 写入到 note.txt 文件中

String filePath = "e:\\note.txt";
        //创建FileWriter对象
        FileWriter fileWriter = null;
        char[] chars = {'a', 'b', 'c'};
        try {
            fileWriter = new FileWriter(filePath);//默认是覆盖写入
//            3) write(int):写入单个字符
            fileWriter.write('H');
//            4) write(char[]):写入指定数组
            fileWriter.write(chars);
//            5) write(char[],off,len):写入指定数组的指定部分
            fileWriter.write("韩顺平教育".toCharArray(), 0, 3);
//            6) write(string):写入整个字符串
            fileWriter.write(" 你好北京~");
            fileWriter.write("风雨之后,定见彩虹");
//            7) write(string,off,len):写入字符串的指定部分
            fileWriter.write("上海天津", 0, 2);
            //在数据量大的情况下,可以使用循环操作.


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

            //对应FileWriter , 一定要关闭流,或者flush才能真正的把数据写入到文件
            //老韩看源码就知道原因.
            /*
                看看代码
                private void writeBytes() throws IOException {
        this.bb.flip();
        int var1 = this.bb.limit();
        int var2 = this.bb.position();

        assert var2 <= var1;

        int var3 = var2 <= var1 ? var1 - var2 : 0;
        if (var3 > 0) {
            if (this.ch != null) {
                assert this.ch.write(this.bb) == var3 : var3;
            } else {
                this.out.write(this.bb.array(), this.bb.arrayOffset() + var2, var3);
            }
        }

        this.bb.clear();
    }
             */
            try {
                //fileWriter.flush();
                //关闭文件流,等价 flush() + 关闭
                fileWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        System.out.println("程序结束...");

五、节点流和处理流

5.1 节点流和处理流基本介绍

1)节点流可以从一个特定的数据源【数据源就是存放数据的地方】读写数据,如FileReader、FileWriter

2)处理流(也叫包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,也更加灵活,如BufferedReader、BufferedWriter

例如 BufferedReader 有属性Reader,既可以封装一个节点流,该节点流可以是任意的,只要是Reader子类

3)节点流和处理流一览图

 5.2 节点流和处理流的区别和联系

(1)节点流是底层流/低级流,直接跟数据源相接;

(2)处理流(包装节)包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来实现输入输出;

(3)处理流(包装流)对节点流进行包装,使用了 修饰器设计模式,不会直接于数据源相连。详见模拟器设计模式。

5.3 处理流主要功能

5.4 处理流-BufferedReader 和 BufferedWriter

注意:BufferedReader和BufferedWriter属于字符流,是按照字符来读取数据的,关闭时,只需要关闭外层流即可。【因为底层会调用的处理流传入的字节流的close方法

5.4.1 案例1:BufferedReader读取文本文件

public class BufferedReader_ {
    public static void main(String[] args) throws Exception {

        String filePath = "e:\\a.java";
        //创建bufferedReader
        BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
        //读取
        String line; //按行读取, 效率高
        //说明
        //1. bufferedReader.readLine() 是按行读取文件
        //2. 当返回null 时,表示文件读取完毕
        while ((line = bufferedReader.readLine()) != null) {
            System.out.println(line);
        }

        //关闭流, 这里注意,只需要关闭 BufferedReader ,因为底层会自动的去关闭 节点流
        //FileReader。
        /*
            public void close() throws IOException {
                synchronized (lock) {
                    if (in == null)
                        return;
                    try {
                        in.close();//in 就是我们传入的 new FileReader(filePath), 关闭了.
                    } finally {
                        in = null;
                        cb = null;
                    }
                }
            }

         */
        bufferedReader.close();

    }
}

5.4.2 案例2:BufferedWriter写入文本文件

public class BufferedWriter_ {
    public static void main(String[] args) throws IOException {
        String filePath = "e:\\ok.txt";
        //创建BufferedWriter
        //说明:
        //1. new FileWriter(filePath, true) 表示以追加的方式写入
        //2. new FileWriter(filePath) , 表示以覆盖的方式写入
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));
        bufferedWriter.write("hello, 韩顺平教育!");
        bufferedWriter.newLine();//插入一个和系统相关的换行
        bufferedWriter.write("hello2, 韩顺平教育!");
        bufferedWriter.newLine();
        bufferedWriter.write("hello3, 韩顺平教育!");
        bufferedWriter.newLine();

        //说明:关闭外层流即可 , 传入的 new FileWriter(filePath) ,会在底层关闭
        bufferedWriter.close();

    }
}

5.4.3 使用BufferedWriter和BufferedReader进行文件拷贝

public class BufferedCopy_ {

    public static void main(String[] args) {


        //老韩说明
        //1. BufferedReader 和 BufferedWriter 是安装字符操作
        //2. 不要去操作 二进制文件[声音,视频,doc, pdf ], 可能造成文件损坏
        //BufferedInputStream
        //BufferedOutputStream
        String srcFilePath = "e:\\a.java";
        String destFilePath = "e:\\a2.java";
//        String srcFilePath = "e:\\0245_韩顺平零基础学Java_引出this.avi";
//        String destFilePath = "e:\\a2韩顺平.avi";
        BufferedReader br = null;
        BufferedWriter bw = null;
        String line;
        try {
            br = new BufferedReader(new FileReader(srcFilePath));
            bw = new BufferedWriter(new FileWriter(destFilePath));

            //说明: readLine 读取一行内容,但是没有换行
            while ((line = br.readLine()) != null) {
                //每读取一行,就写入
                bw.write(line);
                //插入一个换行
                bw.newLine();
            }
            System.out.println("拷贝完毕...");

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流
            try {
                if(br != null) {
                    br.close();
                }
                if(bw != null) {
                    bw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }
}

5.5 处理流-BufferedInputStream 和 BufferedOutputStream

1)BufferedInputStream是字节流,在创建BufferedInputStream时,会创建内部缓冲区数组。

2)BufferedOutputStream是字节流,实现缓冲的输出流,可以将多个字节写入底层输出流中,而不必对每次字节写入调用底层系统。

5.5.1 BufferedInputStream和BufferedOutputStream应用实例

要求:编程实现对音乐/图片 的拷贝(使用Buffered..流)

public class BufferedCopy02 {
    public static void main(String[] args) {

//        String srcFilePath = "e:\\Koala.jpg";
//        String destFilePath = "e:\\hsp.jpg";
//        String srcFilePath = "e:\\0245_韩顺平零基础学Java_引出this.avi";
//        String destFilePath = "e:\\hsp.avi";
        String srcFilePath = "e:\\a.java";
        String destFilePath = "e:\\a3.java";

        //创建BufferedOutputStream对象BufferedInputStream对象
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;

        try {
            //因为 FileInputStream  是 InputStream 子类
            bis = new BufferedInputStream(new FileInputStream(srcFilePath));
            bos = new BufferedOutputStream(new FileOutputStream(destFilePath));

            //循环的读取文件,并写入到 destFilePath
            byte[] buff = new byte[1024];
            int readLen = 0;
            //当返回 -1 时,就表示文件读取完毕
            while ((readLen = bis.read(buff)) != -1) {
                bos.write(buff, 0, readLen);
            }

            System.out.println("文件拷贝完毕~~~");

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

            //关闭流 , 关闭外层的处理流即可,底层会去关闭节点流
            try {
                if(bis != null) {
                    bis.close();
                }
                if(bos != null) {
                    bos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }


    }
}

5.6 对象流-ObjectInputStream 和 ObjectOutputStream(仍是个处理流)

5.6.1 案例引出

看一个需求

1)将int num = 100 这个 int 数据保存到文件中,注意不是100数字,而是int 100,并且,能够从文件中直接恢复int 100

2)将Dog dog = new Dog(“小黄”,3)这个dog对象保存到文件中,并且能够从文件中恢复

上面的要求,就是能够将基本数据类型或者对象进行序列化和反序列化操作

5.6.2 序列化和反序列化

1)序列化就是保存数据时,保存数据的值和数据类型

2)反序列化就是恢复数据时,恢复数据的值和数据类型

3)需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:
Serializable //标记接口,推荐!!,里面无任何方法
Externalizable //该接口有方法需要实现,推荐使用Seralizable接口
 

5.6.3 对象流介绍

  • 功能:提供了对基本类型或者对象类型的序列化和反序列化的方法
  • ObjectOutputStream提供序列化功能
  • ObjectInputStream提供反序列功能

5.6.4 transient关键词

 在持久化对象时,对于一些特殊的数据成员(如用户的密码,银行卡号等),我们不想用序列化机制来保存它。为了在一个特定对象的一个成员变量上关闭序列化,可以在这个成员变量前加上关键字transient。

由此可得出transient的作用:transient是Java语言的关键字,用来表示一个成员变量不是该对象序列化的一部分。当一个对象被序列化的时候,transient型变量的值不包括在序列化的结果中,而非transient型的变量是被包括进去的。 

注意static修饰的静态变量天然就是不可序列化的。

5.6.5 使用ObjectOutputStream进行序列化

要求:使用ObjectOutputStream进行序列化基本数据类型和一个Dog对象(name,age),并保存到data.dat

public class ObjectOutStream_ {
    public static void main(String[] args) throws IOException {
        //序列化后,保存的文件格式,不是存文本,而是按照他的格式来保存
        String filePath = "e:\\data.dat";

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));

        //序列化数据到 e:\data.dat
        oos.writeInt(100);// int -> Integer (实现了 Serializable)
        oos.writeBoolean(true);// boolean -> Boolean (实现了 Serializable)
        oos.writeChar('a');// char -> Character (实现了 Serializable)
        oos.writeDouble(9.5);// double -> Double (实现了 Serializable)
        oos.writeUTF("韩顺平教育");//String
        //保存一个dog对象
        oos.writeObject(new Dog("旺财", 10, "日本", "白色"));
        oos.close();
        System.out.println("数据保存完毕(序列化形式)");
    }
}

//如果需要序列化某个类的对象,实现 Serializable
class Dog implements Serializable {
    private String name;
    private int age;
    //序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员
    private static String nation;
    private transient String color;
    //序列化对象时,要求里面属性的类型也需要实现序列化接口
    private Master master = new Master();

    //serialVersionUID 序列化的版本号,可以提高兼容性
    private static final long serialVersionUID = 1L;

    public Dog(String name, int age, String nation, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
        this.nation = nation;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                '}' + nation + " " +master;
    }

    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;
    }
}

class Master implements Serializable {
}

这里保存到文本文件中出现乱码属于正常现象,关于解决方法,查询了很多资料均未找到有效的解决方法,如有解决方法,求告知。

5.6.6 使用ObjectInputStream进行反序列化

要求:使用ObjectInputStream读取data.dat并反序列化恢复数据

public class ObjectInputStream_ {
    public static void main(String[] args) throws IOException, ClassNotFoundException {

        //指定反序列化的文件
        String filePath = "e:\\data.dat";

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));

        //读取
        //老师解读
        //1. 读取(反序列化)的顺序需要和你保存数据(序列化)的顺序一致
        //2. 否则会出现异常

        System.out.println(ois.readInt());
        System.out.println(ois.readBoolean());

        System.out.println(ois.readChar());
        System.out.println(ois.readDouble());
        System.out.println(ois.readUTF());


        //dog 的编译类型是 Object , dog 的运行类型是 Dog
        Object dog = ois.readObject();
        System.out.println("运行类型=" + dog.getClass());
        System.out.println("dog信息=" + dog);//底层 Object -> Dog

        //这里是特别重要的细节:

        //1. 如果我们希望调用Dog的方法, 需要向下转型
        //2. 需要我们将Dog类的定义,放在到可以引用的位置
        Dog dog2 = (Dog)dog;
        System.out.println(dog2.getName()); //旺财..

        //关闭流, 关闭外层流即可,底层会关闭 FileInputStream 流
        ois.close();


    }
}

5.6.7 注意事项和细节说明

1)读写顺序要一致

2)要求实现序列化或反序列化对象,需要实现Serializable

3)序列化的类中建议添加SerialVersionUID,为了提高版本兼容性

4)序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员

5)序列化对象时,要求里面属性的类型也需要实现序列化接口

6)序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也默认实现了序列化
 

5.7 标准输入流与输出流

5.7.1 基本介绍

//System类的public final static InputStream in = null;
        //System.in 编译类型 InputStream
        //System.in 运行类型 BufferedInputStream
        //表示的是标准输入  键盘
        System.out.println(System.in.getClass());


        //1.System.out public final static Printstream out = null;
        //2.编译类型 PrintStream
        //3.运行类型PrintStream
        //4.表示标准输出  显示器
        System.out.println(System.out.getClass());

 5.7.2 乱码引出转换流

public class CodeQuestion {
    public static void main(String[] args) throws IOException {
        //读取e:\\a.txt 文件到程序
        //思路
        //1.  创建字符输入流 BufferedReader [处理流]
        //2. 使用 BufferedReader 对象读取a.txt
        //3. 默认情况下,读取文件是按照 utf-8 编码
        String filePath = "e:\\a.txt";
        BufferedReader br = new BufferedReader(new FileReader(filePath));

        String s = br.readLine();
        System.out.println("读取到的内容: " + s);
        br.close();

        //InputStreamReader
        //OutputStreamWriter
    }
}

如果将a.txt转换为ANSI,则会出现乱码

5.7.3 转换流-InputStreamReader和OutputStreamWriter

基本介绍:

(1)InputStreamReader:Reader的子类,可以将InputStream(字节流)包装成(转换)Reader(字符流);

(2)OutputStreamWriter:Writer的子类,实现将OutputStream(字节流)包装成Writer(字符流);

(3)当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换为字符流;

(4)可以在使用时指定编码格式(比如utf-8、gbk、gb2312、ISO8859-1等)。

5.7.4 应用案例:使用 InputStreamReader 转换流解决中文乱码问题

要求:编码将字节流FileInputStream包装成字符流InputStreamReader,对文件进行读取按照utf-8格式,进而在包装成BufferedReader

//演示使用 InputStreamReader 转换流解决中文乱码问题
//将字节流 FileInputStream 转成字符流  InputStreamReader, 指定编码 gbk/utf-8
public class InputStreamReader_ {
    public static void main(String[] args) throws IOException {

        String filePath = "e:\\a.txt";
        //解读
        //1. 把 FileInputStream 转成 InputStreamReader
        //2. 指定编码 gbk
        //InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), "gbk");
        //3. 把 InputStreamReader 传入 BufferedReader
        //BufferedReader br = new BufferedReader(isr);

        //将2 和 3 合在一起
        BufferedReader br = new BufferedReader(new InputStreamReader(
                                                    new FileInputStream(filePath), "gbk"));

        //4. 读取
        String s = br.readLine();
        System.out.println("读取内容=" + s);
        //5. 关闭外层流
        br.close();

    }


}

5.7.5 案例2: 把FileOutputStream 字节流,转成字符流 OutputStreamWriter

//        演示 OutputStreamWriter 使用 
//        把FileOutputStream 字节流,转成字符流 OutputStreamWriter
//        指定处理的编码 gbk/utf-8/utf8
public class OutputStreamWriter_ {
    public static void main(String[] args) throws IOException {
        String filePath = "e:\\hsp.txt";
        String charSet = "utf-8";
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath), charSet);
        osw.write("hi, 韩顺平教育");
        osw.close();
        System.out.println("按照 " + charSet + " 保存文件成功~");


    }
}

六、打印流

打印流只有输出流,没有输入流

6.1 PrintStream

public class PrintStream_ {
    public static void main(String[] args) throws IOException {

        PrintStream out = System.out;
        //在默认情况下,PrintStream 输出数据的位置是 标准输出,即显示器
        /*
             public void print(String s) {
                if (s == null) {
                    s = "null";
                }
                write(s);
            }

         */
        out.print("john, hello");
        //因为print底层使用的是write , 所以我们可以直接调用write进行打印/输出
        out.write("韩顺平,你好".getBytes());
        out.close();

        //我们可以去修改打印流输出的位置/设备
        //1. 输出修改成到 "e:\\f1.txt"
        //2. "hello, 韩顺平教育~" 就会输出到 e:\f1.txt
        //3. public static void setOut(PrintStream out) {
        //        checkIO();
        //        setOut0(out); // native 方法,修改了out
        //   }
        System.setOut(new PrintStream("e:\\f1.txt"));
        System.out.println("hello, 韩顺平教育~");


    }
}

6.2 PrintWriter

public class PrintWriter_ {
    public static void main(String[] args) throws IOException {

        //PrintWriter printWriter = new PrintWriter(System.out);
        PrintWriter printWriter = new PrintWriter(new FileWriter("e:\\f2.txt"));
        printWriter.print("hi, 北京你好~~~~");
        printWriter.close();//flush + 关闭流, 才会将数据写入到文件..

    }
}

七、Propertise 类

7.1 基本介绍

(1)专门用于读写配置文件的集合类
       配置文件的格式:

       键=值

(2)注意事项
       键值对不需要有空格,值不需要用引号一起来,默认类型是String。

(3)Properties的常见方法

    load:加载配置文件的键值对到Properties对象;

    list:将数据显示到指定设备;

    getProperty(key):根据键获取值;

    setProperty(key,value):设置键值对到Properties对象【没有就是新建,有就是修改】;

    store:将Properties中的键值对存储到配置文件中,在IDEA中,保存信息到配置文件,如果含有中文,会存储为unicode码。
 

7.2 利用传统方法解决应用实例

 先在src中导入数据

public class Properties_ {
    public static void main(String[] args) throws IOException {
        //读取mysql.properties 文件,并得到ip, user 和 pwd
        BufferedReader br = new BufferedReader(new FileReader("src\\mysql.properties"));
        String line = "";
        while ((line = br.readLine()) != null) { //循环读取
            String[] split = line.split("=");
            //如果我们要求指定的ip值
            if("ip".equals(split[0])) {
                System.out.println(split[0] + "值是: " + split[1]);
            }
        }

        br.close();
    }
}

7.3 Properties类的方法 

 7.3.1 使用Properties类完成对mysql.properties的读取

package properties;

import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;

public class Properties02 {
    public static void main(String[] args) throws IOException {
        //使用Properties类来读取mysql.properties 文件
        //1.创建Properties对象
        Properties properties = new Properties();
        //2.加载指定配置文件
        properties.load(new FileReader("src\\mysql.properties"));
        //3.把k-v显示控制台
        properties.list(System.out);
        //4.根据key获取对应的值
        String user = properties.getProperty("user");
        String pwd = properties.getProperty("pwd");
        System.out.println("用户名="+user);
        System.out.println("密码是="+pwd);
        
    }
}

7.3.2 使用Properties类添加key-val到新文件mysql2.properties中

package properties;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

public class Properties03 {
    public static void main(String[] args) throws IOException {
        //使用Properties类来创建配置文件,修改配置文件内容
        Properties properties = new Properties();
        //创建
        properties.setProperty("charset","utf8");
        properties.setProperty("user","汤姆");//保存是中文的unicode码值
        properties.setProperty("pwd","abc111");
        //将k-v存储文件中即可
        properties.store(new FileOutputStream("src\\mysql2.properties"),null);
        System.out.println("保存配置成功");

    }
}

 7.3.3 使用Properties类完成对mysql.properties的读取,并修改某个key-val

package properties;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

public class Properties03 {
    public static void main(String[] args) throws IOException {
        //使用Properties类来创建配置文件,修改配置文件内容
        Properties properties = new Properties();
        //创建
        //1.如果该文件没有key就是创建
        //2.如果该文件有key就是修改替换
        properties.setProperty("charset","utf8");
        properties.setProperty("user","汤姆");//保存是中文的unicode码值
        properties.setProperty("pwd","88888");//修改密码
        //将k-v存储文件中即可
        properties.store(new FileOutputStream("src\\mysql2.properties"),null);
        System.out.println("保存配置成功");

    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值