JAVA IO操作笔记

目录

  • 0 准备
  • 1 文件
    • 1.1 文件常用操作
      • 1.1.1 创建文件
      • 1.1.2 获取文件信息
      • 1.1.3 文件删除
      • 1.1.4 创建目录
  • 2 IO流
    • 2.1 原理及分类
    • 2.2 常用IO流
      • 2.2.1 文件字节输入流 FileInputStream
      • 2.2.2 文件字节输出流 FileOutputStream
      • 2.2.3 文件字符输入流 FileReader
      • 2.2.4 文件字符输出流 FileWriter
      • 2.2.5 缓冲字节输入流 BufferedInputStream
      • 2.2.6 缓冲字节输出流 BufferedOutputStream
      • 2.2.7 缓冲字符输入流 BufferedReader
      • 2.2.8 缓冲字符输出流 BufferedWriter
      • 2.2.9 对象输字节出流 ObjectOutputStream
      • 2.2.10 对象字节输入流 ObjectInputStream
      • 2.2.11 标准输入输出流 System.in / System.out
      • 2.2.12 转换字符输入流 InputStreamReader (防止中文乱码)
      • 2.2.13 转换字符输出流 OutputStreamWriter (防止中文乱码)
      • 2.2.14 字节打印输出流 PrintStream
      • 2.2.14 字符打印输出流 PrintWriter
      • 2.2.15 配置文件操作 properties



0 准备

需要的依赖

    <dependencies>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.11.0</version>
        </dependency>
        
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>



1 文件

文件在程序中以流的形式来操作的,输入流 与 输出流 中的 输入与输出针对的是内存。
JAVA IO操作笔记_第1张图片
File继承关系
JAVA IO操作笔记_第2张图片

1.1 文件常用操作


1.1.1 创建文件

    /**
     * 创建文件 方法1
     * 

* new File(String pathname) */ @Test public void createFile_test01() { // File对象在内存中 File file = new File("D:\\news1.txt"); try { // 内存中的File对象写入磁盘 file.createNewFile(); System.out.println("文件创建成功"); } catch (IOException e) { e.printStackTrace(); } } /** * 创建文件 方法2 *

* new File(File parent,String child) */ @Test public void createFile_test02() { File parent = new File("D:\\"); String child = "news2.txt"; File file = new File(parent, child); try { file.createNewFile(); System.out.println("创建成功"); } catch (IOException e) { e.printStackTrace(); } } /** * 创建文件 方法3 *

* new File(String parent, String child) */ @Test public void createFile_test03() { File file = new File("D:\\", "news3.txt"); try { file.createNewFile(); System.out.println("创建成功"); } catch (IOException e) { e.printStackTrace(); } }


1.1.2 获取文件信息

    /**
     * 获取文件信息
     */
    @Test
    public void getFileInfo_test01() {
        // 创建文件对象
        File file = new File("D:\\news1.txt");
        // 获取文件名
        System.out.println(file.getName());
        // 获取绝对路径
        System.out.println(file.getAbsolutePath());
        // 获取文件父级目录
        System.out.println(file.getParent());
        // 获取文件字节大小(在utf-8下,一个英文字符是1个字节,一个汉字是3个字节)
        System.out.println(file.length());
        // 判断文件是否存在
        System.out.println(file.exists());
        // 是不是一个文件
        System.out.println(file.isFile());
        // 是不是一个目录
        System.out.println(file.isDirectory());
    }

1.1.3 文件删除

delete删除空目录或文件(delete删除一个目录时,需要确保该目录下面没有文件或者子目录,否则需要先删除文件和字目录)

    /**
     * 判断 “d:\\news1.txt” 是否存在,如果存在就删除
     */
    @Test
    public void deleteFile_test01() {
        String filePath = "d:\\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 deleteFile_test02() { 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("该目录不存在..."); } }

1.1.4 创建目录

mkdir 创建一级目录
mkdirs 创建多级目录

    /**
     * 判断 “D:\\demo\\a\\b\\c” 目录是否存在,如果存在就提示已经存在,否则就创建
     */
    @Test
    public void mkdirs_test01() {
        String directoryPath = "D:\\demo\\a\\b\\c";
        File file = new File(directoryPath);
        if (file.exists()) {
            System.out.println(directoryPath + "存在..");
        } else {
            // 创建一级目录使用mkdir() ,创建多级目录使用mkdirs()
            if (file.mkdirs()) {
                System.out.println(directoryPath + "创建成功..");
            } else {
                System.out.println(directoryPath + "创建失败...");
            }
        }
    }



2 IO流

2.1 原理及分类

io流简介

i/o是input/output的缩写, i/o技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。
java程序中,对于数据的输入/输出操作以“流(stream)” 的方式进行。
java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。

io流原理

输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。
JAVA IO操作笔记_第3张图片
流的分类

(1) 输入输出流
按照流的流向分为输入流和输出流。是以内存的角度来划分。
输入流: 只能读取数据,不能写入。由InputStream 和 Reader作为基类;
输出流: 只能写入数据,不能读取。由OutputStream 和 Writer 作为基类;

(2) 字节流和字符流
字节流:操作数据单元为 8 位字节,由 InputStream 和 OutputStream作为基类;
字符流:操作数据单元为16位字符,由 Reader 和 Writer 作为基类;

(3) 节点流和处理流
按角色分为节点流和处理流。
节点流:从一个特定的IO设备(磁盘,或网络)读写数据的流,称为。
包装流:也叫处理流,对节点流的封装,提供更丰富的功能与更好的性能。
使用装饰器设计模式。


JAVA IO操作笔记_第4张图片

四个基本抽象类

均为抽象类,都需要调用他们的实现子类创建。

在这里插入图片描述

基于以上四个抽象类,根据各种业务场景的需要衍生出如下IO流操作相关类
JAVA IO操作笔记_第5张图片

使用注意事项:

  1. 字符输出流 xxWriter 必须调用 flush()或close() 才能实际写出;
  2. 字符流 会有编码导致的中文乱码问题,所以操作字符流要指定字符编码格式;
  3. 包装流 提供更丰富的功能与更好的性能,一包会在最外层套用包装流;




2.2 常用IO流

2.2.1 文件字节输入流 FileInputStream

read() 方法是一个一个字节去读取,中文一个占三个字节,故会出现乱码,并且效率极低

    /**
     * 方法:
     * public int read() throws IOException
     * 从该输入流读取一个字节的数据。 如果没有输入可用,此方法将阻止。
     * 

* 结果: * 数据的下一个字节,如果达到文件的末尾,-1。 *

* 注意: * 一个中文大于一个字节,中文一定会很乱码。 */ @Test public void test_read() { String filePath = "src\\main\\resources\\fileInputStream"; int readData = 0; InputStream inputStream = null; try { inputStream = new FileInputStream(filePath); while ((readData = inputStream.read()) != -1) { System.out.print((char) readData); // 转换成char显示 } } catch (Exception e) { e.printStackTrace(); } finally { // 一定要关闭文件流,释放资源 IOUtils.closeQuietly(inputStream); } }

一般使用的是 read(byte[] byte) 。一次性读取一个指定长度的字节

    /**
     * 方法:
     * public int read(byte[] b) throws IOException
     * 从该输入流读取最多b.length字节的数据到字节数组。 此方法将阻塞,直到某些输入可用。
     * 

* 参数: * b - 读取数据的缓冲区。取值合理不会出现中文乱码 *

* 结果: * 读入缓冲区的总字节数,如果没有更多的数据,因为文件的结尾已经到达, -1 。 */ @Test public void test_read_bytes() { String filePath = "src\\main\\resources\\fileInputStream"; int readLen = 0; // bytes 取值为中文字符的整数倍则不会中文乱码 byte[] bytes = new byte[3]; InputStream inputStream = null; try { inputStream = new FileInputStream(filePath); while ((readLen = inputStream.read(bytes)) != -1) { // 注意最后一次读取时,bytes不满的情况下,后边不满的几位会缓存上次循环的数据 System.out.print(new String(bytes, 0, readLen)); } } catch (Exception e) { e.printStackTrace(); } finally { // 一定要关闭文件流,释放资源 IOUtils.closeQuietly(inputStream); } }




2.2.2 文件字节输出流 FileOutputStream

    /**
     * 使用FileOutputStream 在a.txt文件,中写入"hello, world"
     * 对于FileOutputStream,如果文件不存在,会创建文件(注意:前提是目录已经存在)
     */
    @Test
    public void test_write() {
        // 创建 FileOutputStream对象
        String filePath = "src\\main\\resources\\a.txt";
        FileOutputStream fileOutputStream = null;
        try {
            // 1. new FileOutputStream(filePath) 创建方式,当写入内容时,会覆盖原来的内容。
            // 2. new FileOutputStream(filePath, true) 创建方式,当写入内容是,是追加到文件后面。
            fileOutputStream = new FileOutputStream(filePath, true);

            // 写入一个字节
            fileOutputStream.write('H');

            // 写入字符串(字符串-> 字节数组)
            String str = "hello,world!";
            fileOutputStream.write(str.getBytes());

            // 截取字符串一部分进行写入 [0,5)
            fileOutputStream.write(str.getBytes(), 0, 5);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(fileOutputStream);
        }
    }
    /**
     * 文件拷贝
     */
    @Test
    public void fileCopy() {
        String inputFilePath = "src\\main\\resources\\王者荣耀.jpg";
        String outFilePath = "src\\main\\resources\\王者荣耀_copy.jpg";
        FileOutputStream fileOutputStream = null;
        FileInputStream fileInputStream = null;
        byte[] buf = new byte[1024];
        int readLength = 0;
        try {
            fileInputStream = new FileInputStream(inputFilePath);
            fileOutputStream = new FileOutputStream(outFilePath, true);

            while ((readLength = fileInputStream.read(buf)) != -1) {
                // 注意:一定要使用这个方法,防止buf缓存倒数第二次结果,可能造成文件损坏
                fileOutputStream.write(buf, 0, readLength);
            }

            System.out.println("文件拷贝成功");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 注意先关闭输入流,在关闭输出流
            IOUtils.closeQuietly(fileInputStream, fileOutputStream);
        }
    }




2.2.3 文件字符输入流 FileReader

可以处理中文字符

    /**
     * 单个字符读取文件(效率很低)
     */
    @Test
    public void readFile01() {
        String filePath = "src\\main\\resources\\a.txt";
        FileReader fileReader = null;
        int data = 0;
        try {
            fileReader = new FileReader(filePath);

            // 循环读取 使用read, 单个字符读取
            while ((data = fileReader.read()) != -1) {
                System.out.print((char) data);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 一定要关闭文件流,释放资源
            IOUtils.closeQuietly(fileReader);
        }
    }

    /**
     * 字符数组读取文件
     */
    @Test
    public void readFile02() {
        String filePath = "src\\main\\resources\\a.txt";
        FileReader fileReader = null;
        int readLen = 0;
        char[] buf = new char[8];
        try {
            fileReader = new FileReader(filePath);
            // 循环读取使用read(buf), 返回的数据缓存在字符数组buf
            // 如果返回-1, 说明到文件结束
            while ((readLen = fileReader.read(buf)) != -1) {
                System.out.print(new String(buf, 0, readLen));
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 一定要关闭文件流,释放资源
            IOUtils.closeQuietly(fileReader);
        }
    }




2.2.4 文件字符输出流 FileWriter

使用FileWriter时 flush()或close必须执行期其中一个,不然无法写入文件

    @Test
    public void write_Test() {
        String filePath = "src\\main\\resources\\b.txt";
        FileWriter fileWriter = null;
        try {
            // 覆盖方式
            // fileWriter = new FileWriter(filePath);
            // 追加方式
            fileWriter = new FileWriter(filePath, true);

            // 1. write(int) 写入单个字符
            fileWriter.write('H');

            // 2. write(char[]): 写入字符数组
            char[] chars = {'a', 'b', 'c'};
            fileWriter.write(chars);// 默认是覆盖

            // 3. write(char[],off,len): 写入字符数组的截取部分
            fileWriter.write("李淳罡--陆地神仙境".toCharArray(), 0, 3);

            // 4. write(String) :写入整个字符串
            fileWriter.write("你好啊北京");

            // 5. write(string,off,len):写入字符串的截取部分
            fileWriter.write("李白--诗仙", 0, 2);
            // 在数据量比较大的时候采用循环才做

            // 注意:flush()或close() 必须执行期其中一个,否则不会输出到文件
            // 因为实际写出到文件的操作在这两个方法中被调用
            fileWriter.flush();

            System.out.println("文件输出成功");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 一定要关闭文件流,释放资源
            IOUtils.closeQuietly(fileWriter);
        }
    }




2.2.5 缓冲字节输入流 BufferedInputStream

    @Test
    public void test_readLine() {
        String filePath = "src\\main\\resources\\a.txt";
        int readLen = 0;
        byte[] buf = new byte[1024]; // 取值为中文字符的整数倍则不会中文乱码

        BufferedInputStream bufferedInputStream = null;
        try {
            bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath));

            while ((readLen = bufferedInputStream.read(buf)) != -1) {
                System.out.println(new String(buf, 0, readLen));
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭装饰流,实际会关闭其内部持有的节点流
            IOUtils.closeQuietly(bufferedInputStream);
        }
    }




2.2.6 缓冲字节输出流 BufferedOutputStream

    @Test
    public void test_copy() {
        String inputFilePath = "src\\main\\resources\\王者荣耀.jpg";
        String outputFilePath = "src\\main\\resources\\王者荣耀_copy1.jpg";
        byte[] buf = new byte[1024];
        int readLen;

        BufferedInputStream bufferedInputStream = null;
        BufferedOutputStream bufferedOutputStream = null;
        try {
            bufferedInputStream = new BufferedInputStream(new FileInputStream(inputFilePath));
            bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(outputFilePath));

            while ((readLen = bufferedInputStream.read(buf)) != -1) {
                // 注意:一定要使用这个方法,防止buf缓存倒数第二次结果,可能造成文件损坏
                bufferedOutputStream.write(buf, 0, readLen);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭装饰流,实际会关闭其内部持有的节点流
            IOUtils.closeQuietly(bufferedInputStream, bufferedOutputStream);
        }
    }




2.2.7 缓冲字符输入流 BufferedReader

BufferedReader属于字符流,是按照字符读取数据的,所以最好处理文本文件,像图片,声音这种字节组织的二进制文件的话,用字符流读取可能会造成文件损失,所以最好使用字节流。

    @Test
    public void test_readLine() {
        String filePath = "src\\main\\resources\\a.txt";
        BufferedReader bufferedReader = null;
        try {
            // 创建 BufferedReader
            bufferedReader = new BufferedReader(new FileReader(filePath));
            // 按行读取,效率高
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭装饰流,实际会关闭其内部持有的节点流
            IOUtils.closeQuietly(bufferedReader);
        }
    }




2.2.8 缓冲字符输出流 BufferedWriter

BufferedWriter属于字符流,是按照字符读取数据的,所以最好处理文本文件,像图片,声音这种字节组织的二进制文件的话,用字符流读取可能会造成文件损失,所以最好使用字节流。

    @Test
    public void test_write() {
        String filePath = "src\\main\\resources\\d.txt";
        BufferedWriter bufferedWriter = null;
        try {
            // 覆盖的方式
            // bufferedWriter = new BufferedWriter(new FileWriter(filePath));
            // 追加的方式
            bufferedWriter = new BufferedWriter(new FileWriter(filePath, true));
            for (int i = 0; i < 3; i++) {
                bufferedWriter.write("你好啊,boy!");
                bufferedWriter.newLine();
                bufferedWriter.write("你好啊,小胖子!");
                bufferedWriter.write("你好啊,girls!");

                // 注意:flush()或close() 必须执行期其中一个,否则不会输出到文件
                // 因为实际写出到文件的操作在这两个方法中被调用
                bufferedWriter.flush();
            }

            System.out.println("写出完成");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭装饰流,实际会关闭其内部持有的节点流
            IOUtils.closeQuietly(bufferedWriter);
        }
    }
    /**
     * 文件拷贝
     * 

* 不要去操作 二进制文件[声音,视频,doc, pdf 等], 可能造成文件损坏!! */ @Test public void test_copy() { String inputFilePath = "src\\main\\resources\\a.txt"; String outputFilePath = "src\\main\\resources\\a_copy.txt"; BufferedWriter bufferedWriter = null; BufferedReader bufferedReader = null; try { bufferedReader = new BufferedReader(new FileReader(inputFilePath)); bufferedWriter = new BufferedWriter(new FileWriter(outputFilePath)); String readLine; while ((readLine = bufferedReader.readLine()) != null) { bufferedWriter.write(readLine); // readLine读取一行的时候没有读取换行符 bufferedWriter.newLine(); } System.out.println("完成拷贝..."); } catch (IOException e) { e.printStackTrace(); } finally { // 关闭装饰流,实际会关闭其内部持有的节点流 IOUtils.closeQuietly(bufferedReader, bufferedWriter); } }




2.2.9 对象输字节出流 ObjectOutputStream

将 java对象 序列化后输出到文件(要求 java对象支持序列化)

public class Dog implements Serializable {
    private String name;
    private int age;

    public Dog(String name, int age) {
        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 "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
    /**
     * 序列化输出到文件
     */
    @Test
    public void test() {
        // 序列化之后,保存的文件格式,不是存文本,而是按照他的格式来保存
        String filePath = "src\\main\\resources\\dog.dat";
        ObjectOutputStream objectOutputStream = null;
        try {
            objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath));

            objectOutputStream.writeInt(100);         // int -> Integer (实现了 Serializable)
            objectOutputStream.writeBoolean(true);    // boolean -> Boolean (实现了 Serializable)
            objectOutputStream.writeChar('a');        // char -> Character (实现了 Serializable)
            objectOutputStream.writeDouble(9.5);      // double -> Double (实现了 Serializable)
            objectOutputStream.writeUTF("莫寒寒来咯!"); // String (实现了 Serializable)
            objectOutputStream.writeObject(new Dog("旺财", 10)); // Dog (实现了 Serializable)

            System.out.println("序列化输出成功...");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭装饰流,实际会关闭其内部持有的节点流
            IOUtils.closeQuietly(objectOutputStream);
        }
    }




2.2.10 对象字节输入流 ObjectInputStream

将文件中的数据读取并反序列化为 java对象 (要求 java对象支持序列化)

   /**
     * 序列化输出到文件
     */
    @Test
    public void test() {
        String filePath = "src\\main\\resources\\dog.dat";
        ObjectInputStream objectInputStream = null;
        try {
            objectInputStream = new ObjectInputStream(new FileInputStream(filePath));

            // 注意:读取反序列化的顺序需要和保存数据序列化的顺序一致,否则会出异常
            System.out.println(objectInputStream.readInt());
            System.out.println(objectInputStream.readBoolean());
            System.out.println(objectInputStream.readChar());
            System.out.println(objectInputStream.readDouble());
            System.out.println(objectInputStream.readUTF());

            Object dog = objectInputStream.readObject();
            Dog dog1 = (Dog) dog;
            System.out.println(dog1);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭装饰流,实际会关闭其内部持有的节点流
            IOUtils.closeQuietly(objectInputStream);
        }
    }

对象处理流使用细节

  1. 必须读写顺序一致,否则抛出异常;
  2. 必须去实现 Serializable 接口,否则抛出异常;
  3. 序列化的类中建议添加 serialVersionUID ,为了提高版本的兼容性
    // 序列化的版本号,可以提高兼容性 
    private static final long serialVersionUID = 1L;
  1. 序列化的时候不会序列化 static 或 transient 修饰的字段;
    private static String nation;
    private transient String color;
  1. 序列化的时候,要求里边的属性也必须要实现序列化接口;
  2. 序列化有继承性;




2.2.11 标准输入输出流 System.in / System.out

    public static void main(String[] args) {
        // System.in 编译类型 InputStream
        // System.in 运行类型 BufferedInputStream
        // 表示标准输入--键盘
        System.out.println(System.in.getClass());

        // System.out 编译类型 PrintStream
        // System.out 运行类型 PrintStream
        // 表示标准输出--显示器
        System.out.println(System.out.getClass());
        
        Scanner scanner = new Scanner(System.in);
        System.out.println("输入内容");
        String next = scanner.next();
        System.out.println("next=" + next);
    }




2.2.12 转换字符输入流 InputStreamReader (防止中文乱码)

转换流可以将字节流转换成字符流

字符编码不统一导致的中文乱码问题

    /**
     * 测试编码导致的 "中文乱码" 问题
     */
    @Test
    public void test_code_question() {
        //思路
        //1. 创建字符输入流 BufferedReader [处理流]
        //2. 使用 BufferedReader 对象读取文件
        //3. 默认情况下,读取文件是按照 utf-8 编码
        String filePath = "src\\main\\resources\\a_gbk.txt";![在这里插入图片描述](https://img-blog.csdnimg.cn/6cb75e4a21f44bf581f772dbaddbe82f.png)

        BufferedReader bufferedReader = null;
        try {
            // 创建 BufferedReader
            bufferedReader = new BufferedReader(new FileReader(filePath));
            // 按行读取,效率高
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭装饰流,实际会关闭其内部持有的节点流
            IOUtils.closeQuietly(bufferedReader);
        }
    }

文件采用 gbk 的编码方式,内容如下:
JAVA IO操作笔记_第6张图片

因为编码问题到导致的乱码结果
JAVA IO操作笔记_第7张图片

采用转换流解决中文乱码问题

    /**
     * 使用 InputStreamReader 转换流解决中文乱码问题
     * 将字节流 FileInputStream 转成字符流 InputStreamReader, 指定编码 gbk
     */
    @Test
    public void test_read_code() {
        String filePath = "src\\main\\resources\\a_gbk.txt";
        BufferedReader bufferedReader = null;
        try {
            // 把 FileInputStream 转成 InputStreamReader,并指定编码 gbk
            InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(filePath), "gbk");
            // 使用缓冲流,按行读取,效率高(可以不使用)
            bufferedReader = new BufferedReader(inputStreamReader);
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭最外层的装饰流,实际会关闭其内部持有的节点流
            IOUtils.closeQuietly(bufferedReader);
        }
    }

转换流指定的编码格式必须和文本编码一致,否则会中文乱码




2.2.13 转换字符输出流 OutputStreamWriter (防止中文乱码)

转换流可以将字节流转换成字符流

    /**
     * 使用 OutputStreamWriter 转换流解决中文乱码问题
     * 将字节流 FileOutputStream 转成字符流 OutputStreamWriter, 指定编码 gbk
     */
    @Test
    public void test_write_code() {
        String filePath = "src\\main\\resources\\gbk.txt";

        BufferedWriter bufferedWriter = null;
        try {
            // 把 FileOutputStream 转成 OutputStreamWriter,并指定编码 gbk
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(filePath), "gbk");
            // 使用缓冲流,按行读取,效率高(可以不使用)
            bufferedWriter = new BufferedWriter(outputStreamWriter);
            bufferedWriter.write("hi");
            bufferedWriter.newLine();
            bufferedWriter.write("hello,world!");
            bufferedWriter.newLine();
            bufferedWriter.write("中国浙江杭州");
            bufferedWriter.newLine();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭最外层的装饰流,实际会关闭其内部持有的节点流
            IOUtils.closeQuietly(bufferedWriter);
        }
    }




2.2.14 字节打印输出流 PrintStream

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

    /**
     * 演示PrintStream (字节打印流/输出流)
     */
    @Test
    public void test_write() throws IOException {
        String filePath = "src\\main\\resources\\PrintStream.txt";

        PrintStream out = System.out;
        // 在默认情况下,PrintStream 输出数据的位置是 标准输出,即显示器
        out.print(" hello ");
        // 因为print底层使用的是write , 所以我们可以直接调用write进行打印/输出
        out.write(" 你好 ".getBytes());

        // 可以去修改打印流输出的 位置/设备
        System.setOut(new PrintStream(filePath));
        System.out.println("hello, PrintStream~");

        out.close();
    }



2.2.14 字符打印输出流 PrintWriter

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

    /**
     * 演示 PrintWriter 使用方式
     */
    @Test
    public void test_write() throws IOException {
        String filePath = "src\\main\\resources\\PrintWriter.txt";

        // 写到控制台
        // PrintWriter printWriter = new PrintWriter(System.out);
        // 写入文件
        PrintWriter printWriter = new PrintWriter(new FileWriter(filePath));
        printWriter.print("hi, 你好~~~~");

        // 注意:flush()或close必须执行期其中一个,否则不会输出到文件
        printWriter.close();
    }

2.2.15 配置文件操作 properties

    /**
     * 读取 properties 配置文件
     */
    @Test
    public void test_read() throws IOException {
        String filePath = "src\\main\\resources\\mysql.properties";

        // 1. 创建一个Properties对象
        Properties properties = new Properties();
        // 2. 加载指定配置文件
        properties.load(new FileReader(filePath));
        // 3. 把k-v显示到控制台
        properties.list(System.out);
        // 4. 根据key 获取对应的值
        String username = properties.getProperty("username");
        System.out.println("username=" + username);
        String password = properties.getProperty("password");
        System.out.println("password=" + password);
    }

    /**
     * 写入 properties 配置文件
     */
    @Test
    public void test_write() throws IOException {
        String filePath = "src\\main\\resources\\mysql.properties";

        // 使用Properties类来创建配置文件, 修改配置文件的内容
        Properties properties = new Properties();
        properties.setProperty("charset", "utf8");
        properties.setProperty("user", "小明");
        // 底层是个hashTable,不允许重复,如果存在,则替换。
        properties.setProperty("user", "小红");

        properties.store(new FileOutputStream(filePath), "hello world");
        System.out.println("保存文件成功");
    }

你可能感兴趣的:(Java,java,开发语言,后端)