07.java-IO流

07. IO流

01. 文件

1. 什么是文件

​ 文件对我们并不陌生,文件是保存数据的地方,比如大家经常使用的word文档,txt文件,excel文件…都是文件。它既可以保存一张图片,可以保存视频,声音

2.文件流

​ 文件在程序中是以流的形式来操作的
在这里插入图片描述

  1. :数据在数据源(文件)和程序(内存)之间的经历的路径
    2. 输入流:数据从数据源(文件)到程序(内存)的路径
    3. 输出流:数据从程序(内存)到数据源(文件)的路径

02. 常用的文件操作

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

1. 相关方法:
  1. new File(String pathname)//根据路径构建一个File对象
  2. new File(File parent, String child)//根据父目录文件+子路径构建
  3. new File(String parent, String child)//根据父目录+子路径构建
  4. createNewFile 创建新文件
2. 应用案例

要求:在E盘下,创建文件 news1.txt news2.txt news3.txt

import jdk.jfr.StackTrace;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.IOException;


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

    }
    @Test
    //1. 方式一:new File(String pathname)
    public void create01() {
        String filePath = "e:\\news1.txt";
        File file = new File(filePath);
        try {
            file.createNewFile();
            System.out.println("文件创建成功");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Test
    //2. 方式二:new File(File parent, String child)//根据父目录文件+子路径构建
    public void creat02() {
        File file = new File("e:\\");
        String fileName = "news2.txt";
        File file1 = new File(file, fileName);
        try {
            file1.createNewFile();
            System.out.println("文件创建成功");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Test
    //3. 方式三:new File(String parent, String child)//根据父目录+子路径构建
    public void creat03() {
        String parentPath = "e:\\";
        String childPath = "news3.txt";
        File file = new File(parentPath, childPath);
        try {
            file.createNewFile();
            System.out.println("文件创建成功");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2. 获取文件的相关信息

1. 方法

​ getName、getAbsolutePath、getParent、Length、exists、isFile、isDirectory

2. 应用案例
import java.io.File;

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

    }
    @Test
    //1. 获取文件的信息
    public void inf() {
        //1.1 先创建文件对象
        File file = new File("e:\\news1.txt");
        //1.2 调用相应的方法,得到对应的信息
        //1.3getName、getAbsolutePath、getParent、Length、exists、isFile、isDirectory
        System.out.println("文件的名字=" + file.getName());
        System.out.println("文件的绝对路径=" + file.getAbsolutePath());
        System.out.println("文件的父级目录=" + file.getParent());
        System.out.println("文件的大小(字节)=" + file.length());
        System.out.println("文件是否存在" + file.exists());
        System.out.println("是不是一个文件" + file.isFile());
        System.out.println("是不是一个目录" + file.isDirectory());

    }
}

3. 目录的操作和文件删除

1. 方法

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

2. 应用案例
package com.yzjedu.file;

import org.junit.jupiter.api.Test;

import java.io.File;

/**
 * 03. 目录的操作和文件删除
 **/
public class Directory_ {
    public static void main(String[] args) {

    }
    @Test
    //1.判断 e:\\news1.txt 是否存在,如果存在就删除
    public void m1() {
        String filePath = "e:\\news1.txt";
        File file = new File(filePath);
        if (file.exists()) {
            if (file.delete()) {
                System.out.println("删除成功");
            } else {
                System.out.println("删除失败");
            }
        }else {
            System.out.println("文件不存在");
        }
    }
    @Test
    //2. 判断e:\\demo02 是否存在,存在就删除,否则提示不存在
    //体会,在java编程中,目录也被当做一种文件存在
    public void m2() {
        String filePath = "e:\\demo02";
        File file = new File(filePath);
        if (file.exists()) {
            if (file.delete()) {
                System.out.println("删除成功");
            } else {
                System.out.println("删除失败");
            }
        }else {
            System.out.println("该目录不存在");
        }
    }
    @Test
    //3. 判断e:\\demo\\a\\b\\c 目录是否存在,如果存在就提示已经存在,否则就创建
    public void m3() {
        String directoryPath = "e:\\demo\\a\\b\\c";
        File file = new File(directoryPath);
        if (file.exists()) {
            System.out.println(directoryPath + "存在");
        }else {
            if (file.mkdirs()) {
                System.out.println(directoryPath + "创建成功");
            } else {
                System.out.println("创建失败");
            }
        }
    }
}

03. Java IO流原理及流的分类

1. Java IO流原理

  1. I/O是Input/Output的缩写,I/O技术是非常实用的技术, 用于处理数据传输。如读/写文件,网络通讯等。
  2. Java程序中,对于数据的输入/输出操作以”流(stream)"的方式进行。
  3. java.io包下提供了各种“流"类和接口,用以获取不同种类的数据,并通过方法输入或输出数据
  4. 输入input: 读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
  5. 输出output: 将程序(内存)数据输出到磁盘、光盘等存储设备中

2. 流的分类

  1. 按操作数据单位不同分为: 字节流(8 bit) 二进制文件, 字符流(按字符) 文本文件
  2. 按数据流的流向不同分为: 输入流,输出流
  3. 按流的角色的不同分为:节点流,处理流/包装流
(抽象基类)字节流字符流
输入流InputStreamReader
输出流OutputStreamWriter
  1. Java的I0流共涉及40多个类,实际上非常规则,都是从如上4个抽象基类派生的。
  2. 由这四个类派生出来的子类名称都是以其父类名作为子类名后缀。

3. 流和文件的区别

  1. 流是数据的抽象和传输方式,而文件是数据的存储形式。
  2. 流是实时的、动态的,而文件是静态的、持久的。
  3. 流通常用于数据的临时传输和处理,而文件用于长期存储和持久化。

04. IO体系-常用的类

1. InputStream(字节输入流)

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

2. InputStream常用的子类

  1. FileInputStream: 文件输入流
  2. BufferedInputStream:缓冲字节输入流
  3. ObjectInputStream:对象字节输入流

3. FileInputStream应用实例

**要求:**使用FileInputStream 在 a.txt文件,写入“hello,world”,如果文件不存在,会创建文件(注意:前提是目录已经存在)

import org.junit.jupiter.api.Test;

import java.io.FileInputStream;
import java.io.IOException;

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

    }

    /**
     * 演示读取文件
     */
    @Test
    public void readFile01() {
        String filePath = "d:\\hello.txt";
        FileInputStream fileInputStream = null;
        //2. 字节数组
        byte[] buf = new byte[8];//2.1 一次读取8个字节
        int readLen = 0;

        try {
            //1. 创建 FileInputStream 对象,用于读取文件
            fileInputStream = new FileInputStream(filePath);
            //1.1 从改输入流读取一个字节的数据。如果没有输入可用,此方法将阻止
            //1.2 如何返回-1,表示读取完毕
            //2.2 如果读取正常,返回实际读取的字节数
            while ((readLen = fileInputStream.read(buf)) != -1) {
               System.out.print(new String(buf, 0, readLen));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

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

4. FileOutputStream

1. 介绍

​ 该类的主要作用是创建一个输出流,使程序能够将数据写入文件。通过 FileOutputStream 类,可以逐字节地将数据写入文件,也可以一次性写入字节数组。

2. FileOutputStream应用实例1

​ 要求: 请使用 FileOutputStream 在 a.txt 文件,中写入 “hello,world”, 如果文件不存在,会创建 文件(注意:前提是目录已经存在.)

import org.junit.jupiter.api.Test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

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

    }

    /**
     * 演示使用FileOutputStream 将数据写到文件中
     * 如果文件不存在,则创建该文件
     */
    @Test
    public void writeFile() {
        //1. 创建 FileOutputStream 对象
        String filePath = "d:\\a.txt";
        FileOutputStream fileOutputStream = null;


        try {
            //1.1 得到FileOutputStream对象
            //2. new FileOutputStream(filePath) 创建方式,当写入内容时,会覆盖原来的内容
            //2.1 new FileOutputStream(filePath, true) 创建方式,当写入入内容时,会增加到文件的末尾
            fileOutputStream = new FileOutputStream(filePath, true);
            //1.2 写入一个字节
//            fileOutputStream.write('H');
            //1.3 写入字符串
            String str = "hello,world!";
            //getBytes() 这个方法的作用可以把 字符串 -> 字节数组
//            fileOutputStream.write(str.getBytes());
            //1.4 write(byte[] b, int off, int len) 方法二
            fileOutputStream.write(str.getBytes(), 0, /*str.length()将所有的字符串内容写入*/ 3);
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
3. FileOutputStream应用实例2

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

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileCopy {
    public static void main(String[] args) {
        //1. 完成文件拷贝,将d:\\pg.png 拷贝 c:\\
        //2. 思路分析
        //2.1 创建文件的输入流,将文件读入到程序
        //2.2 创建文件的如初六,将读取到的文件数据,写入到指定的文件
        String srcFilePath = "d:\\bg.png";
        String destFilePath = "d:\\bg2.png";
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            fileInputStream = new FileInputStream(srcFilePath);
            fileOutputStream = new FileOutputStream(destFilePath);
            //3. 定义一个字节数组,提高读取效果
            byte[] buf = new byte[1024];
            int readLen = 0;
            while ((readLen = fileInputStream.read(buf)) != -1) {
                //3.1 读取到后,就写入到文件,通过 fileOutputStream
                //3.2 即 边读边写
                fileOutputStream.write(buf, 0, readLen);

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

5. FileReader和FileWriter

1. 介绍
FileReader

作用: FileReader 用于读取字符文件中的数据。
特点: 它是从文件中读取字符数据的便捷类,通常与 BufferedReader 结合使用,以提高读取效率。
构造方法:
FileReader(File file):根据指定的文件创建一个新的 FileReader。
FileReader(String fileName):根据指定的文件名创建一个新的 FileReader。

FileWriter

作用: FileWriter 用于向文件中写入字符数据。
特点: 它是从文件中写入字符数据的便捷类,通常与 BufferedWriter 结合使用,以提高写入效率。
构造方法:
FileWriter(File file):根据指定的文件创建一个新的 FileWriter。
FileWriter(String fileName):根据指定的文件名创建一个新的 FileWriter。

2. FileReader常用方法
  1. new FileReader(File/String)
  2. read: 每次读取单个字符,返回该字符,如果到文件未尾返回-1
  3. read(char[]): 批量读取多个字符到数组,返回读取到的字符数,如果到文件未尾返回-1
    相关API:
  4. new String(char[]): 将char[]转换成String
  5. new String(char[],off,len): 将char[]的指定部分转换成String
3. FileWriter常用方法
  1. new FileWriter(File/String):覆盖模式,相当于流的指针在首端
  2. new FileWriter(File/String,true):追加模式,相当于流的指针在尾端
  3. write(int):写入单个字符
  4. write(char[]):写入指定数组
  5. write(char[],off,len):写入指定数组的指定部分
  6. write (string) :写入整个字符串
  7. write(string,off,len):写入字符串的指定部分
    相关API:String类: toCharArray:将String转换成char[]
    注意:FileWriter使用后,必须要关闭(close)或刷新(flush), 否则写入不到指定的文件!
4. FileReader和FileWriter应用案例
要求:
  1. 使用FileReader从story.txt 读取内容,并显示
import org.junit.jupiter.api.Test;

import java.io.FileReader;
import java.io.IOException;


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

    }

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

        //1. 创建FileReader对象
        try {
            fileReader = new FileReader(filePath);
            //2. 循环读取 使用read, 8个字符读取
            while ((readLen = fileReader.read(buf)) != -1) {
                System.out.print(new String(buf, 0, readLen));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fileReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
  1. 使用 FileWriter 将 “风雨之后,定见彩虹” 写入到 note.txt 文件中, 注意细节
import java.io.FileWriter;
import java.io.IOException;


public class FileWriter_ {
    public static void main(String[] args) {
        String filePath = "d:\\note.txt";
        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("加油加油", 0, 3);
//            6.  write (string) :写入整个字符串
            fileWriter.write(" 你好,我来了");
            fileWriter.write("风雨之后,定见彩虹");//完成要求
//            7.  write(string,off,len):写入字符串的指定部分
            fileWriter.write("真的是好像吃饭", 0, 3);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //8. 对于FileWriter, 一定要关闭流,或者flush才能真正把数据写入到文件
            try {
                fileWriter.flush();
              //fileWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("程序结束");
    }
}

05. 节点流和处理流

1. 基本介绍

1. 节点流:

​ 节点流可以从一个特定的数据源读写数据,如FileReader、FileWriter
想象一下你需要从一个水源中直接取水。节点流就像是直接与数据源连接的水龙头,它们直接读取或写入数据到数据源。
​ 在Java中,节点流直接与文件、网络连接或内存数据相连,可以实现基本的读写操作。

2. 处理流

​ 处理流(也叫包装流)是"连接”在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,也更加灵活,如BufferedReader/BufferedWriter
​ 现在想象一下你在取水时使用了一个过滤器或者水桶来处理水流。处理流就像是对节点流的增强,它们提供了更高级别的功能和操作。
​ 处理流不直接与数据源相连,而是对节点流进行包装,并提供了缓冲、转换、过滤等功能。

2. 节点流和处理流的区别和联系

  1. 节点流是底层流/低级流,直接跟数据源相接。
  2. 处理流(包装流)包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。[源码理解]
  3. 处理流(也叫包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连[模拟修饰器设计模式]

3. 处理流的功能主要体现在以下两个方面

  1. 性能的提高:主要以增加缓冲的方式来提高输入输出的效率。
  2. 操作的便捷:处理流可能提供了一系列便捷的方法来一 次输入输出大批量的数据,使用更加灵活方便

4. 处理流-BufferedReader和BufferedWriter

1. BufferedReader应用案例

要求:使用BufferedReader读取文本文件,并显示在控制台

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;

public class BufferedReader_ {
    public static void main(String[] args) throws Exception {
        String filePath = "d:\\a.txt";
        //1. 创建BufferedReader
        BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
        //2. 读取
        String line;//2.1 按行读取
        //说明:
        //1. bufferedReader.readLine();按行读取文件
        //2. 当返回null时,表示文件读取完毕
        while ((line = bufferedReader.readLine()) != null) {
            System.out.println(line);
        }
        //关闭流,这里注意,只需要关闭 BufferedReader,因为底层会自动去关闭 节点流
        bufferedReader.close();
    }
}
2. BufferedWriter应用案例

要求使用BufferedWriter将“你好,我可以进来吗”,写入到文件中

import java.io.*;

public class BufferWriter_ {
    public static void main(String[] args) throws IOException {
        String filePath = "d:\\a.txt";
        //创建BufferedWriter对象
        //说明:
        //1. new FileWriter(filePath, true) 表示以追加的方式写入
        //2. new FileWriter(filePath) 表示已覆盖的方式写入
        BufferedWriter bufferedWriter = null;
        bufferedWriter = new BufferedWriter(new FileWriter(filePath,true));
        bufferedWriter.write("你好,我可以进来吗");
        bufferedWriter.newLine();
        bufferedWriter.write("你好,我可以进来吗");
        bufferedWriter.newLine();
        bufferedWriter.write("你好,我可以进来吗");
        //插入一个换行

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


    }
}
3. 综合案例

要求:综合使用BufferedReader和BufferedWriter完成文本文件的拷贝,注意文件编码

import java.io.*;

public class BufferedCopy_{
    public static void main(String[] args) {
        String srcFilePath = "d:\\a.txt";
        String destFilePath = "d:\\a2.txt";
        BufferedReader bufferedReader = null;
        BufferedWriter bufferedWriter = null;
        //说明:
        //1. BufferedReader和BufferedWriter是安装字符操作
        //2. 不要操作二进制文件,可能造成文件损坏

        try {
            bufferedReader = new BufferedReader(new FileReader(srcFilePath));
            bufferedWriter = new BufferedWriter(new FileWriter(destFilePath));
            String Line;
            //1. 读取文件内容
            while ((Line = bufferedReader.readLine()) != null) {
                //2. 每读取一行,就写入
                bufferedWriter.write(Line);
                //2.1 插入一个换行
                bufferedWriter.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
                if (bufferedWriter != null) {
                    bufferedWriter.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

5. 处理流-BufferedInputStream 和 BufferedOutputStream

1. 介绍BufferedInputStream

​ BufferedInputStream是字节流,在创建BufferedInputStream时,会创建-个内部缓冲区数组.

2. 介绍bufferedOutputStream

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

3. 应用案例

要求:编程完成图片/音乐的拷贝(要求使用Buffered…流)

package com.yzjedu.outputstream_;

import java.io.*;

/**
 * @author Icaru
 * @version 1.0
 * @date 2024/3/3 20:58
 * 13.
 */
public class BufferedCopy02 {
    public static void main(String[] args) {
        String srcFilePath = "d:\\win.jpg";
        String destFilePath = "d:\\win2.jpg";

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

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

            //2. 循环读取文件,并写入到 destFilePath
            byte[] buff = new byte[1024];
            int readLen = 0;
            while ((readLen = bis.read(buff)) != -1) {
                bos.write(buff, 0, readLen);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //3. 关闭外层流即可,底层会自动关闭节点流
            try {
                if (bis != null) {
                    bis.close();
                }
                if (bos != null) {
                    bis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

6. 对象流-ObjectInputStream 和 ObjectOutputStream

1. 看一个需求
  1. 将int num = 100这个int数据保存到文件中,注意不是100数字,而是int 100,井且,能够从文件中直接恢复int 100
  2. 将Dog dog = new Dog(”小黄”,3)这个dog对象保存到文件中,并且能够从文件恢复.
  3. 上面的要求, 就是能够将基本数据类型或者对象进行序列化和反序列化操作
2. 序列化和反序列化
  1. 序列化就是在保存数据时, 保存数据的值数据类型
  2. 反序列化就是在恢复数据时,恢复数据的值数据类型
  3. 需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:
    Serializable // 这是一个标记接口,没有方法
    Externalizable //该接口有方法需要实现,因此我们一般实现上面的Serializable接口
3. 对象流介绍

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

4. 应用案例
  1. 要求:使用ObjectOutputStream序列化基本数据类型和一个Dog对象(name, age), 并保存到data.dat文件中
import java.io.*;

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

        //2. 序列化数据到 e:\data
        oos.write(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
        //保存一个对象
        oos.writeObject(new Dog("旺财", 10));
        oos.close();
        System.out.println("数据保存完成(序列化形式)");
    }
}
class Dog implements Serializable {
    private String name;
    private int age;

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
  1. 使用ObjectInputStream读取data.dat并反序列化恢复数据
import com.yzjedu.outputstream_.Dog;

import java.io.*;

public class ObjectInputStream_ {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //1. 制定反序列化的文件
        String filePath = "d:\\data.dat";
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
        //2. 读取(反序列化)的顺序需要和你保存数据(序列化)的顺序一致
        //2.1 否则会出现异常

        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());
        //3.2 dog 的编译类型是Object,dog运行类型是Dog
        Object dog = ois.readObject();
        System.out.println("运行类型" + dog.getClass());
        System.out.println("dog信息 = " + dog);

        //3. 这里是特别重要的细节:
        //3.1 如果我们希望调用Dog方法,需要向下转型
        //3.2 需要我们将Dog类的定义,拷贝到可以引用的位置
        Dog dog2 =(Dog)dog;
        System.out.println(((Dog) dog).getName());

        //关闭流, 只关闭外层流即可
        ois.close();
    }
}

**注意:**假如我们要反序列化,记得将上一个ObjectOutputStream_类中的Dog类移出,设置为public类,这样反序列化,就不会出现毛病

5. 注意事项和细节说明
  1. 读写顺序要一致
  2. 要求序列化或反序列化对象,需要实现Serializable
  3. 序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性
//1.还记得我们的上个案例中的Dog类吗
//1.1 在它的属性中添加
 private static final long serialVersionUID = 1L;
//1.2 添加后就可以进行序列化和反序列化时,在Dog类中添加其他的属性不会影响其序列化(反序列化),提高了版本兼容性
  1. 序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员
  2. 序列化对象时,要求里面属性的类型也需要实现序列化接口
    1. 这句话的意思是,当你要将一个对象序列化成字节流保存到文件或者通过网络传输时,这个对象的所有属性都需要是可序列化的。也就是说,对象的属性类型必须要实现Serializable接口,否则在序列化过程中会抛出NotSerializableException异常
  3. 序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化

7. 标准输入输出流

1. 介绍
类型默认设备
System.in 标准输入InputStream键盘
System.out 标准输出PrintStream显示器
2. 应用案例
  1. 传统方法System.out.println(“”); 是使用out对象将数据输出到显示器
  2. 传统方法,Scanner是从标准输入 键盘接受数据
import java.util.Scanner;

public class InputAndOutput {
    public static void main(String[] args) {
        //1. System 类 的 public final static InputStream in = null;
        //1.1 System.in 编译类型 InputStream
        //1.2 System.in 运行类型 BufferedInputStream
        //1.3 表示是标准输入 键盘
        System.out.println(System.in.getClass());

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

        System.out.println("hello,world!");
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入内容:");
        String next = scanner.next();
        System.out.println(next);

    }
}

8. 转换流-InputStreamReader 和 OutputStreamWriter

1. 引出问题

​ 在前面的内容中我们经常见到创建的文件有乱码问题,那么我们该如何解决乱码问题,这就要引出转换流。让我们先写一段代码,看看乱码的问题

import java.io.*;

public class CodeQuestion {
    public static void main(String[] args) throws IOException {
        /*
        看一个乱码问题
     */
        //1. 创建字符输入流 BufferedReader [处理流]
        //2. 使用 BufferedReader 对象读取 a.txt
        //3. 默认情况下,读取文件是按照 utf-8 编码
        //4. 如果你将文件修改为其他编码例如国标码,你会发现文件出现乱码
        String filePath = "d:\\a.txt";
        BufferedReader br = new BufferedReader(new FileReader(filePath));
        String s = br.readLine();
        System.out.println("读取到的内容是:" + s);
        br.close();
    }
}
2. 介绍
  1. InputStreamReader:Reader的子类,可以将InputStream(字节流)包装成(转换)Reader(字符流)
  2. OutputStreamWriter:Writer的子类,实现将OutputStream(字节流)包装成Writer(字符流)
  3. 当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流
  4. 可以在使用时指定编码格式(比如utf-8, gbk,gb2312, IS08859-1等)
3. 应用案例
  1. 编程将字节流FilelnputStream 包装成(转换成)字符流InputStreamReader,对文件进行读取(按照utf-8/gbk格式),进而在包装成BufferedReader
import java.io.*;

public class InputStreamReader_ {
    public static void main(String[] args) throws IOException {
        String filePath = "d:\\a.txt";
        //解读
        //1. 把FileInputStream 转成 InputStreamReader
        //2. 指定编码 gbk
        //InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), "gbk");
        //3. 把InputStreamReader 传入 BufferedReader
        //BufferedReader br = new BufferedReader(isr);

        //5. 一般情况下我们可以将2 和 3 结合起来
        BufferedReader br = new BufferedReader(new InputStreamReader(
                new FileInputStream(filePath),"gbk"));

        //4. 读取
        String s = br.readLine();
        System.out.println("读取内容= " + s);
        br.close();

    }
}
  1. 编程将字节流FileOutputStream 包装成(转换成) 字符流OutputStreamWriter,对文件进行写入(按照gbk格式,可以指定其他,比如utf-8)
import com.yzjedu.writer_.BufferWriter_;

import java.io.*;

/**
 * 演示 OutputStreamWriter 使用
 * 把FileOutputStream 字节流,转成 OutputStreamWriter
 * 指定处理的编码 gbk/utf-8/utf8
 */
public class OutputStreamWriter {
    public static void main(String[] args) throws IOException {
        String filePath = "d:\\a.txt";
        String charSet = "utf-8";
        BufferedWriter osw = new BufferedWriter(new java.io.OutputStreamWriter(
                new FileOutputStream(filePath), charSet));
        osw.newLine();
        osw.write("你好,hello!");
        osw.close();
        System.out.println("按照 " + charSet + " 保存文件成功");


    }
}

9. 打印流-PrintStream和PrintWriter

1. 介绍

​ 打印流(PrintStream和PrintWriter)是Java中的输出流类,它们使得将数据输出到文件、控制台或网络等目标变得更加简单。PrintStream用于处理字节流数据,而PrintWriter则处理字符流数据。
**注意:**打印流只有输出流,没有输入流

2. 应用实例
  1. PrintStream案例
import java.io.IOException;
import java.io.PrintStream;

public class PrintStream_ {
    public static void main(String[] args) throws IOException {
        PrintStream out = System.out;
        //1. 在默认情况下,PrintStream输出数据的位置是 标准输出,即显示器
        /*
        public void print(String s) {
            if (s == null) {
                s = "null";
            }
            write(s);
        }
         */
        out.print("java,i like");
        //1.1 因为print的底层使用的是Write,所以我们可以直接调用write进行打印/输出
        out.write("lmf,你好".getBytes());

        //2. 我们可以去修改打印流输出的位置/设备
        //2.1 输出修改成了"d:\\f1.txt"
        //2.2 "hello, lmf" 会打印到f1.txt的位置
        System.setOut(new PrintStream("d:\\f1.txt"));
        System.out.println("hello, lmf");
    }
}
  1. PrintWriter案例
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class PrintWrite_ {
    public static void main(String[] args) throws IOException {
//        PrintWriter printWriter = new PrintWriter(System.out);
        PrintWriter printWriter = new PrintWriter(new FileWriter("d:\\f2.txt"));
        printWriter.print("hi, 天津你好");
        printWriter.close();//注意要记得关闭,如果没有关闭,不会输出
    }
}

10. Properties类

1. 看一个需求

如下一个配置文件 mysql.properties
ip: 192.168.0.13
ueser=root
pwd=12345

请问编程读取ip、user和pwd的值是多少

分析
  1. 传统方法
import javax.sound.sampled.Line;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Properties01 {
    public static void main(String[] args) throws IOException {
        //1. 读取mysql.properties 文件,并得到ipk, user 和 pwd
        BufferedReader bufferedReader = new BufferedReader(
                new FileReader("src\\mysql.properties"));
        String line = "";
        while ((line = bufferedReader.readLine()) != null) {//循环读取
            String[] parts = line.split("=");
            System.out.println(parts[0] + "值是:" + parts[1]);
        }
    }
}

如果我们只取ip,我们还要手动去写"ip".equals(split[0]) 判断,比较麻烦

2. 基本介绍
  1. 专门用于读写配置文件的集合类
    配置文件的格式:
    键=值
    键=值
  2. 注意:键值对不需要有空格,值不需要用引号括起来。默认类型是String
  3. Properties的常用方法
    1. load:加载配置文件的键值对到Properties对象
    2. list:将数据显示到指定设备/流对象
    3. getProperty(key):根据键获取值
    4. setProperty(key,value):设置键值对到Properties对象
    5. store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果含有中文,会存储为unicode码
3. 应用案例
  1. 使用Properties类完成对mysql.properties的读取
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;

/**
 * 演示Properties类 来读取mysql.properties
 */
public class Properties02 {
    public static void main(String[] args) throws IOException {

        //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的值是" + user);
        System.out.println("pwd的值是" + pwd);
    }
}
  1. 使用Properties类添加key-val 到新文件mysql2.properties 中
  2. 使用Properties类完成对mysql2.properties的读取,并修改某个key-val
/**
  * 演示Properties 类来配置文件,修改配置文件的内容
 */
public class Properties03 {
    public static void main(String[] args) throws IOException {
        Properties properties = new Properties();
        //创建
        //1. 如果该文件没有key 就是创建
        //2. 如果该文件有key 就是修改
        //3. Properties 父类是 Hashtable底层就是Hashtable的核心方法
        properties.setProperty("charset", "utf-8");
        properties.setProperty("user","江南");//注意保存时,中文是unicode码值
        properties.setProperty("pwd","bdhs");

        //将k-v存储到一个文件
        properties.store(new FileOutputStream("src\\mysql2.properties"),"hello"/*这是一个注释,可以为空*/);
        System.out.println("保存配置文件成功");
    }
}
  • 15
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: B'15.java中IO分为几种?' A: 在Java中,IO分为四种类型:字节(InputStream, OutputStream)和字符(Reader, Writer),又分为输入和输出。 ### 回答2: 在 Java 中,IO 可以分为四种类型:字节、字符、缓冲和数据。 1. 字节:字节以字节为单位读取和写入数据,通常用于读取和写入二进制文件,如图像和音频文件。字节分为输入和输出,分别用于从文件读取数据和将数据写入文件。 2. 字符:字符以字符为单位读取和写入数据,通常用于读取和写入文本文件。与字节不同,字符不仅可以读取和写入纯文本数据,还可以处理其他格式的文本数据,如 XML 和 HTML。 3. 缓冲:缓冲提高了 IO 操作的效率,在读写数据时预读和预写数据,将数据先存储在缓存区中,再逐块传输。这些可以加快程序处理大文件和大数据量的速度。 4. 数据:数据是一种特殊的字节,可以方便地读取和写入 Java 基本数据类型和对象。它具有多种方法可以读取或写入整数、字符串、布尔值等等。 总之,Java 中的 IO 提供灵活和易于使用的方式来读取和写入数据。无论您要读取或写入二进制文件、文本文件或其他格式的数据,都可以使用适当类型的 IO 。 ### 回答3: Java中的IO主要分为4类:输入、输出、字符和字节。 输入用于读取数据,可分为字节输入和字符输入。字节输入读取字节数据,字符输入读取字符数据。常用的字节输入包括FileInputStream、ObjectInputStream、ByteArrayInputStream等;常用的字符输入包括FileReader、InputStreamReader等。 输出用于写入数据,可分为字节输出和字符输出。字节输出写入字节数据,字符输出写入字符数据。常用的字节输出包括FileOutputStream、ObjectOutputStream、ByteArrayOutputStream等;常用的字符输出包括FileWriter、OutputStreamWriter等。 字符和字节的主要区别在于字节是以字节为单位进行输入输出的,而字符则是以字符为主,同时字符会对数据进行编码解码操作,而字节不会。 除了字节和字符,Java还提供了处理二进制数据的RandomAccessFile类,以及用于序列化和反序列化对象的ObjectInputStream和ObjectOutputStream类。 总之,Java中的IO提供了丰富的API和功能,开发者可以根据不同的需求选择合适的IO实现代码功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值