Java--IO流

一、IO流概述

1.1、什么是IO

生活中,你肯定经历过这样的场景。当你编辑一个文本文件,忘记了ctrl+s ,可能文件就白白编辑了。当你电脑上插入一个U盘,可以把一个视频,拷贝到你的电脑硬盘里。那么数据都是在哪些设备上的呢?键盘、内存、硬盘、外接设备等等。

我们把这种数据的传输,可以看做是一种数据的流动,按照流动的方向,以内存为基准,分为输入input输出output ,即流向内存是输入流,流出内存的输出流。

Java中I/O操作主要是指使用java.io包下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做作写出数据。

I:input 输入(读取)

O:output 输出(写入)

流:数据(字符,字节) 1字符 = 2字节 1字节 = 8二进制位

1.2、IO的分类

根据数据的流向分为:输入流输出流

  • 输入流 :把数据从其他设备上读取到内存中的流。
  • 输出流 :把数据从内存 中写出到其他设备上的流。

根据数据的类型分为:字节流字符流

  • 字节流 :以字节为单位,读写数据的流。
  • 字符流 :以字符为单位,读写数据的流。

1.3、顶级父类们

二、字节流

2.1、一切皆为字节

一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。

在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。

2.2、字节输出流

java.io.OutputStream抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。

  • close():关闭此输出流并释放与此流相关联的任何系统资源。
  • flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
  • write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。
  • write(byte[] b, int off, int len):从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
  • write(int b):将指定的字节输出流。

由于java.io.OutputStream是一个抽象类,所以只能使用它的子类

注意:close方法,当完成流的操作时,必须调用此方法,释放系统资源。

2.3、FileOutputStream类

OutputStream有很多子类,我们从最简单的一个子类开始。

java.io.FileOutputStream类:文件字节输出流,用于将内存中数据写出到硬盘的文件中。

2.3.1、构造方法

  • FileOutputStream(File file):创建文件输出流以写入由指定的 File对象表示的文件。
  • FileOutputStream(String name): 创建文件输出流以指定的名称写入文件。

参数:写入数据的目的地

构造方法的作用

  • 创建一个FileOutputStream对象
  • 会根据构造方法中传递的文件/文件路径,创建一个空的文件。如果有这个文件,会清空这个文件的数据。
  • 会把FileOutputStream对象指向创建好的文件

2.3.2、写入数据的原理

内存 —> 硬盘
Java程序 —> JVM(Java虚拟机) —> OS(操作系统) —> OS调用写数据的方法 —> 把数据写到文件中

2.3.3、字节输出流的使用步骤

  • 创建一个FileOutputStream对象,构造方法中传递写入数据的目的地
  • 调用FileOutputStream对象中的write方法,把数据写入到文件中
  • 释放资源(流的使用会占用一定的内存,使用完毕需要把内存释放掉,提高程序的效率)
  • public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
  • public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
  • public abstract void write(int b) :将指定的字节输出流。

写出字节数据

// 测试OutputStream子类
public class OutputStream {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("a.txt");
        fos.write(97);
        fos.close();
    }
}

文件存储的原理

  • 通过FileOutputStream对象中的路径创建文件
  • 调用write方法,写数据的时候,会把十进制整数转换为二进制整数

记事本打开文件的原理

  • 在打开文件的时候,都会查询编码表,把字节转换为字符表示
  • 0-127:查询ASCII表
  • 其他值查询系统默认编码表(中文系统查询GBK编码表)

一次写多个字节的方法

  • public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。
  • public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
// 一次写多个字节的方法
public class Demo2OutputStream {
    public static void main(String[] args) throws Exception {
        // 创建FileOutputStream对象,构造方法中绑定要写入数据的目的地
        FileOutputStream fos = new FileOutputStream(new File("b.txt"));
        // 调用FileOutputStream对象中的方法write,把数据写入到文件中
        // 在文件中显示100,需要写3个字节
        fos.write(49);
        fos.write(48);
        fos.write(48);

        /*
            一次写多个字节:
                如果写的第一个字节是正数(0-127),那么显示的时候会查询ASCII码表
                如果写的第一个字节是负数,那么第一个字节会和第二个字节,两个字节组成一个中文显示,查询系统默认码表
         */
        byte[] bytes = {65, 66, 67, 68, 69};
        fos.write(bytes);

        byte[] bytes2 = {-65, 66, -67, 68};
//        fos.write(bytes2);  // 如果要打印下面的“你好”,需要注释这里
        // 文件中的结果:100ABCDE緽紻,一共12个字节。

        /*
            把字节数组的一部分写入到文件中
            write(byte[] b, int off, int len)`
            off:数组的开始索引
            len:写几个字节
         */
        fos.write(bytes, 1, 2); // 写入BC

        /*
            写入字符串的方法:可以使用String类中的方法,把字符串转换为字节数组
            byte[] getBytes():把字符串转换为字节数组
         */
        byte[] bytes1 = "你好".getBytes();
        System.out.println(Arrays.toString(bytes1)); // [-28, -67, -96, -27, -91, -67],IDEA使用的utf-8三个字节为一个中文,GBK两个字节为一个中文
        fos.write(bytes1);


        // 释放资源
        fos.close();
    }
}

数据追加续写

  • public FileOutputStream(File file, boolean append): 创建文件输出流以写入由指定的 File对象表示的文件。
  • public FileOutputStream(String name, boolean append): 创建文件输出流以指定的名称写入文件。
  • 参数:
    • file/name:写入数据的目的地
    • append:追加写开关。true,创建不会覆盖原文件,继续在文件的末尾追加写数据。false,创建新文件,覆盖原文件

换行符号

windows:\r\n
linux:/n
mac:/r

// 追加写/续写,使用两个参数的构造方法即可
// 换行
public class Demo3OutputStream {
    public static void main(String[] args) throws Exception {
        FileOutputStream fos = new FileOutputStream("c.txt", true);
        for (int i = 0; i <= 10; i++) {
            fos.write("你好".getBytes());
            fos.write("\r\n".getBytes());
        }

        fos.close();
    }
}

2.4、字节输入流

java.io.InputStream抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。

  • public void close() :关闭此输入流并释放与此流相关联的任何系统资源。
  • public abstract int read(): 从输入流读取数据的下一个字节。
  • public int read(byte[] b): 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。

2.5、FileInputStream类

java.io.FileInputStream类:文件输入流,从文件中读取字节。可以把硬盘文件中的数据读取到内存中使用

2.5.1、构造方法

  • FileInputStream(File file): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
  • FileInputStream(String name): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。
  • 参数:读取文件的数据源
    • file:文件
    • name:文件路径
  • 作用
    • 创建一个FileInputStream对象
    • 把FileInputStream对象指向构造方法中要读取的文件

2.5.2、读取数据原理

硬盘 —> 内存
Java程序 —> JVM —> OS —> OS读取数据的方法 —> 读取文件

2.5.3、字节输入流的使用步骤

  1. 创建FileInputStream对象,构造方法中绑定要读取的数据源
  2. 使用FileInputStream对象中的read方法读取文件
  3. 释放资源
  • public void close() :关闭此输入流并释放与此流相关联的任何系统资源。
  • public abstract int read(): 从输入流读取数据的下一个字节。
// 测试字节输入流
// 定义了所有子类共性的方法
public class Demo1InputStream {
    public static void main(String[] args) throws Exception {
        // 创建FileInputStream对象
        FileInputStream fis = new FileInputStream("a.txt");
        // read方法读取文件
        // 读取文件中的一个字节并返回,读取到文件的末尾会返回-1
        // 每读一次,都会把指针向后移一位
//        int len = fis.read();
//        System.out.println(len); // 97

        /*
            读取文件其实是一个重复的过程,所以可以使用循环优化
            不知道文件中有多少字节,使用while循环
            while循环的结束条件:读取到-1的时候结束
         */
        // 记录读取到的字节
        int len2 = 0;
        while ((len2 = fis.read()) != -1) {
            System.out.println((char)len2); // 使用char会把97转为a
        }

        fis.close();
    }
}

一次读取多个字节
public int read(byte[] b): 从输入流中读取一些字节数,并将它们存储到字节数组 b中。

数组的作用:

  • 缓冲作用,存储读取到的多个字节
  • 一般定义为1024(1kb),或者是1024的整数倍
public class FISRead {
    public static void main(String[] args) throws IOException{
        FileInputStream fis = new FileInputStream("b.txt"); // 文件中为abcde
        // 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b中
        byte[] bytes = new byte[2];
        int len = fis.read(bytes);
        System.out.println(len); // 2,表示每次读取字节的个数
        /*
            String(byte[] bytes):把字节数组转换为字符
            String(byte[] byte, int offset, int length):把字节数组的一部分转为字符串。offset:数组的开始索引  length:转换字节个数
         */
        System.out.println(Arrays.toString(bytes)); // [65, 66]
        System.out.println(new String(bytes));// ab
    }
}

输出结果:
ab
cd
ed

结果中的ed是由于每次读取时都会覆盖数组的上一条数据,读到e时,只替换了c

优化:

public class FISRead {
    public static void main(String[] args) throws IOException{
        FileInputStream fis = new FileInputStream("b.txt"); // 文件中为abcde
        // 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b中
        byte[] bytes = new byte[2];
        int len = fis.read(bytes);
        System.out.println(len); // 2,表示每次读取字节的个数
        /*
            String(byte[] bytes):把字节数组转换为字符
            String(byte[] byte, int offset, int length):把字节数组的一部分转为字符串。offset:数组的开始索引  length:转换字节个数
         */
        System.out.println(Arrays.toString(bytes)); // [65, 66]
        System.out.println(new String(bytes, 0, len));// ab
    }
}

2.6、图片复制

文件复制练习:一读一写

文件复制的步骤:

  1. 创建一个字节输入流对象,构造方法中绑定要读取的数据源
  2. 创建一个字节输出流对象,构造方法中绑定要写入的目的地
  3. 使用字节输入流对象中的read方法读取文件
  4. 使用字节输出流对象中的write方法写入文件
  5. 释放资源
public class Demo1CopyFile {
    public static void main(String[] args) throws Exception {
        FileInputStream fis = new FileInputStream("E:\\money.jpg");
        FileOutputStream fos = new FileOutputStream("E:\\money001.jpg");
        // 读取一个字节写入一个字节的方式
//        int len = 0;
//        while ((len = fis.read()) != -1) {
//            fos.write(len);
//        }

        // 读一个写一个太慢,优化成读取多个字节,写入多个字节的方法
        byte[] bytes = new byte[1024]; // 最好是1024的整数倍
        int len = 0; // 记录每次读取的有效字节个数
        while ((len = fis.read(bytes)) != -1) {
            fos.write(bytes, 0, len);
        }

        // 释放资源
        // 先关闭写的,再关闭读的。因为如果写完了,就一定读完了
        fos.close();
        fis.close();
    }
}

三、字符流

当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。

使用字节流读取中文文件:
1个中文
​ GBK:占用两个字节
​ UTF-8:占用三个字节

public class Demo01InputStream {
    public static void main(String[] args) throws Exception {
        FileOutputStream fos = new FileOutputStream("c.txt");
        byte[] bytes = "你好".getBytes();
        System.out.println(Arrays.toString(bytes)); // [-28, -67, -96, -27, -91, -67]
        fos.write(bytes);
        fos.close();

        FileInputStream fis = new FileInputStream("c.txt");
        int len = 0;
        while ((len = fis.read()) != -1) {
            System.out.println(len);
        }
        fis.close();
        
        /*
        	228
            189
            160
            229
            165
            189
         */
    }
}

在main方法中String的getBytes()方法如果不指定编码格式,默认是UTF-8的方法进行的编码
Tomcat在启动的时候将file.encoding指定成了gbk.所以在Servlet中获取字节码数组的时候,默认用的就是gbk.
Tomcat是根据当前操作系统来设置file.encoding的值,电脑是windows简体中文的.所以默认就是GBK的

1、对于字节流来说,从输入流里读取的字节编码取决于被读取的文件自身的编码,输出流生成的文件编码取决于字节编码。

2、对于字符流来说,其底层仍为字节流操作,所以输入流读取文件可以看做是把文件读取成字节,然后字节再转换为字符。这就涉及到两个过程,第一个过程与字节流读取一样,但是第二个过程new InputStreamReader(inputStream)即字节转字符时InputStreamReader()默认是utf-8编码,如果字节的编码不是utf-8,那么转换过程就会出错,所以这里转换编码要和文件编码一致,可以在转换时指定转换的编码new InputStreamReader(inputStream,“gbk”);同样,输出流与此相反,生成文件的编码取决于new OutputStreamReader()时的编码,作为中间载体的字符是统一的char,所以只要保证转换时的编码与文件编码一致即可保证无乱码,无需输入流与输出流编码一致。

3.1、字符输入流【Reader】

java.io.Reader抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。

  • public void close() :关闭此流并释放与此流相关联的任何系统资源。
  • public int read(): 从输入流读取一个字符。
  • public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。

3.2 FileReader类

java.io.FileReader:文件字符输入流,把硬盘中文件中的数据以字符的方式读取到内存中。构造时使用系统默认的字符编码和默认字节缓冲区。

注意:

  1. 字符编码:字节与字符的对应规则。Windows系统的中文编码默认是GBK编码表。idea中是UTF-8
  2. 字节缓冲区:一个字节数组,用来临时存储字节数据。

3.2.1、构造方法

  • FileReader(File file): 创建一个新的 FileReader,给定要读取的File对象。
  • FileReader(String fileName): 创建一个新的 FileReader,给定要读取的文件的名称。
    • 参数:filename代表文件路径,file代表一个文件

作用:

  1. 创建一个FileReader对象
  2. 会把FileReader对象指向要读取的文件

3.2.2、使用步骤

  1. 创建FileReader对象,构造方法中绑定要读取的数据源

  2. 使用FileReader对象中的方法read读取文件

  3. 释放资源

    public class Demo02Reader {
        public static void main(String[] args) throws Exception {
            // 1. 创建FileReader对象,构造方法中绑定要读取的数据源
            FileReader fr = new FileReader("c.txt");
            // 2. 使用FileReader对象中的方法read读取文件
            // 读取单个
    //        int len = 0;
    //        while ((len = fr.read()) != -1) {
    //            System.out.println((char)len);
    //        }
    
            // 读取多个字符
            char[] cs = new char[1024]; // 存储读取到的多个字符
            int len = 0; // 记录的是每次读取的有效字符个数
            while ((len = fr.read(cs)) != -1) {
                /*
                    String(char value[]):把字符数组转为字符串
                    String(char value[], int offset, int count):把字符数组一部分转为字符串。offset表示开始的索引,count表示个数
                 */
                System.out.println(new String(cs, 0, len));
            }
            fr.close();
        }
    }
    

3.3、字符输出流【Writer】

java.io.Writer抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法。

  • void write(int c) 写入单个字符。
  • void write(char[] cbuf)写入字符数组。
  • abstract void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
  • void write(String str)写入字符串。
  • void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
  • void flush()刷新该流的缓冲。
  • void close() 关闭此流,但要先刷新它。

3.4 FileWriter类

java.io.FileWriter:文件字符输出流。把内存中字符数据写入到文件中。构造时使用系统默认的字符编码和默认字节缓冲区。

3.4.1、构造方法

  • FileWriter(File file): 创建一个新的 FileWriter,给定要读取的File对象。
  • FileWriter(String fileName): 创建一个新的 FileWriter,给定要读取的文件的名称。
    • 参数:filename代表文件路径,file代表一个文件

作用:

  1. 会创建一个FileWriter对象
  2. 会根据构造方法中传递的文件/文件路径创建一个文件
  3. 会把FileWriter对象指向创建好的文件

3.4.2、使用步骤

  1. 创建FileWriter对象,构造方法中绑定要写入数据的目的地

  2. 使用FileWriter中的方法write,把数据写入到缓冲区中(字符转换为字节的过程)

  3. 使用FileWriter中的方法flush,把内存缓冲区的数据,刷新到文件中

  4. 释放资源(会把内存缓冲区中的数据刷新到文件中)

    public class Demo03Writer {
        public static void main(String[] args) throws Exception {
            // 1. 创建FileWriter对象,构造方法中绑定要写入数据的目的地
            FileWriter fw = new FileWriter("d.txt");
            // 2. 使用FileWriter中的方法write,把数据写入到缓冲区中(字符转换为字节的过程)
            fw.write(97);
            // 3. 使用FileWriter中的方法flush,把内存缓冲区的数据,刷新到文件中
            fw.flush();
            // 4. 释放资源(会把内存缓冲区中的数据刷新到文件中)
            fw.close();
        }
    }
    

注意:

  1. 虽然参数为int类型四个字节,但是只会保留一个字符的信息写出。
  2. 未调用close方法,数据只是保存到了缓冲区,并未写出到文件中。

3.4.3、关闭和刷新

因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush 方法了。

  • flush :刷新缓冲区,流对象可以继续使用。

  • close:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。

    public class Demo04CloseAndFlush {
        public static void main(String[] args) throws Exception {
            // 1. 创建FileWriter对象,构造方法中绑定要写入数据的目的地
            FileWriter fw = new FileWriter("d.txt");
            // 2. 使用FileWriter中的方法write,把数据写入到缓冲区中(字符转换为字节的过程)
            fw.write(97);
            // 3. 使用FileWriter中的方法flush,把内存缓冲区的数据,刷新到文件中
            fw.flush();
            // 刷新之后,流可以继续使用
            fw.write(98);
            // 4. 释放资源(会把内存缓冲区中的数据刷新到文件中)
            fw.close();
    
            // close方法之后,流已经关闭了,已经从内存中消失了,就不能再使用了
            fw.write(99); // IOException: Stream closed
        }
    }
    

注意:即便是flush方法写出了数据,操作的最后还是要调用close方法,释放系统资源。

3.4.4、写数据的其他方法

public class Demo05Writer {
    public static void main(String[] args) throws Exception {
        FileWriter fw = new FileWriter("f.txt");
        char[] cs = {'a', 'b', 'c', 'd', 'e'};
        // write(char[] cbuf):写出字符数组
        fw.write(cs);
        // write(char[] cbuf, int off, int len):写入字符数组的某一部分,off数组的开始索引,len写的字符个数
        fw.write(cs, 1, 3);
        // write(String str):写字符串
        fw.write("测试");
        // write(String str, int off, int len):写字符串的一部分
        fw.write("字符输出流", 2, 3);
        fw.close();
    }
}

3.4.5、续写和换行

续写:使用两个参数的构造方法

  • FileWriter(String fileName, boolean append)
  • FileWriter(File file, boolean append)
    • fileName和file表示写入数据的目的地。
    • append表示续写开关,true不会创建新的文件覆盖原文件,可以续写。flase会创建新文件覆盖

换行:换行符号

  • windows:\r\n

  • linux:\n

  • mac:\r

    public class Demo06Writer {
        public static void main(String[] args) throws Exception {
            FileWriter fw = new FileWriter("g.txt", true);
            for (int i = 0; i < 10; i++) {
                fw.write("hello world" + i + "\r\n");
            }
            fw.close();
        }
    }
    

四、IO异常的处理

在JDK1.7之前,可以使用try...catch...finally处理流中的异常

/* 
格式:
try{
	可能会产生异常的代码
}catch(异常变量  变量名) {
	异常的处理逻辑
}finally {
    一定会指定的代码
    资源释放
}
 */

public class Demo01TryCatch {
    public static void main(String[] args) {
        // 变量在定义的时候可以没有值,但是使用的时候必须有值
        FileWriter fw = null;
        try{
            // 可能会产生异常的代码
            fw = new FileWriter("g.txt", true);
            for (int i = 0; i < 10; i++) {
                fw.write("hello world" + i + "\r\n");
            }
        }catch (IOException e) {
            System.out.println(e);
        }finally {
            // 如果创建对象失败了,fw的默认值是null,会抛出空指针异常
            if (fw != null) {
                try {
                    // fw.close()声明抛出了IO异常对象所以就得处理这个异常对象,要么throws,要么try...catch
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

JDK7的新特性:在try的后面可以增加一个(),在括号中可以定义流对象
那么这个流对象的作用域就在try中有效
try中代码执行完毕,会自动地把流对象释放,不用写finally

/*
格式:
try(定义流对象;定义流对象) {
	可能会产生异常的代码
}catch(异常变量  变量名) {
	异常的处理逻辑
}
 */

public class Demo02JDK7 {
    public static void main(String[] args) {
        try (
             FileInputStream fis = new FileInputStream("E:\\money.jpg");
             FileOutputStream fos = new FileOutputStream("E:\\money001.jpg");) {

            // 可能会产生异常的代码
            byte[] bytes = new byte[1024];
            int len = 0; // 记录每次读取的有效字节个数
            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
            }
        }catch (IOException e) {
            System.out.println(e);
        }
    }
}

JDK9的新特性:在try的前面可以定义流对象,在try后面的()中可以直接引入流对象的名称。在try代码块执行完毕后,流对象也可以释放掉,不用写finally

/*
格式:
A a = new A();
B b = new B();
try(a, b) {
	可能会产生异常的代码
}catch(异常变量  变量名) {
	异常的处理逻辑
}
 */

public class Demo03JDK9 {
    public static void main(String[] args) throws FileNotFoundException {
        FileInputStream fis = new FileInputStream("E:\\money.jpg");
        FileOutputStream fos = new FileOutputStream("E:\\money001.jpg");
        try (fis; fos) {
            // 可能会产生异常的代码
            byte[] bytes = new byte[1024];
            int len = 0; // 记录每次读取的有效字节个数
            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
            }
        }catch (IOException e) {
            System.out.println(e);
        }
    }
}

五、属性集

5.1、概述

java.util.Properties 继承于Hashtable ,来表示一个持久的属性集,可以保存在流中或从流中加载。

它使用键值结构存储数据,每个键及其对应值都是一个字符串。该类也被许多Java类使用,比如获取系统属性时,System.getProperties 方法就是返回一个Properties对象。

Properties集合是唯一一个和IO流相结合的集合

可以使用Properties集合中的方法store,把集合中的临时数据,持久化到硬盘中存储

可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对)读取到集合中使用

属性列表中每个键及其对应值都是一个字符串

Properties是一个双列集合,key和value默认都是字符串

5.2、Properties类

5.2.1、构造方法

  • public Properties() :创建一个空的属性列表。

5.2.2、基本的存储方法

  • Object setProperty(String key, String value) : 调用Hashtable的方法put

  • String getProperty(String key) :通过key找到value值,相当于Map中的get方法

  • Set<String> stringPropertyNames() :所有键的名称的集合。

    public class Demo01Properties {
        public static void main(String[] args) {
            show01();
        }
    
        private static void show01() {
            // 创建properties集合对象
            Properties prop = new Properties();
            // 使用setProperty在集合中添加数据
            prop.setProperty("小明", "168");
            prop.setProperty("小红", "160");
            prop.setProperty("小强", "165");
            // 使用stringPropertyNames获取全部的key
            Set<String> set = prop.stringPropertyNames();
            // 使用getProperty取出每一个value
            for (String key : set) {
                String value = prop.getProperty(key);
                System.out.println(key + "=" + value);
            }
        }
    }
    

5.2.3、与流相关的方法—store

  • store(OutputStream out, String comments):把集合中的临时数据,持久化到硬盘中存储

  • store(Writer writer, String comments):把集合中的临时数据,持久化到硬盘中存储

    • OutputStream out:字节输出流,不能写入中文
    • Writer writer:字符输出流,可以写中文
    • String comments:解释说明保存的文件是做什么用的,不能使用中文,会产生乱码,默认是unicode编码,一般使用空字符串

使用步骤

  1. 创建Properties集合对象,添加数据

  2. 创建字节输出流/字符输出流对象,构造方法中绑定要输出的目的地

  3. 使用Properties集合中的方法store,把集合中的临时数据持久化到硬盘中存储

    public class Demo01Properties {
        public static void main(String[] args) throws Exception {
            show02();
        }
    
        private static void show02() throws Exception {
            // 创建Properties集合对象,添加数据
            Properties prop = new Properties();
            // 使用setProperty在集合中添加数据
            prop.setProperty("小明", "168");
            prop.setProperty("小红", "160");
            prop.setProperty("小强", "165");
    
            // 创建字节输出流/字符输出流对象,构造方法中绑定要输出的目的地
            FileWriter fw = new FileWriter("prop.txt");
            // 使用Properties集合中的方法store,把集合中的临时数据持久化到硬盘中存储
            prop.store(fw, "save data");
        }
    }
    

与流相关的方法—load

  • public void load(InputStream inStream): 从字节输入流中读取键值对。
  • public void load(Reader reader): 从字节输入流中读取键值对。
    • InputStream inStream:字节输入流,不能读取含有中文的键值对
    • Reader reader:字符输入流,能读取含有中文的键值对

使用步骤

  1. 创建Properties集合对象
  2. 使用Properties集合对象中的方法load,读取保存键值对的文件
  3. 遍历Properties集合

注意:

  1. 存储键值对的文件中,键与值默认的连接符号可以使用=,空格(其他符号)
  2. 存储键值对的文件中,可以使用#进行注释,被注释的键值对不会再被读取
  3. 存储键值对的文件中,键与值都是字符串,不用再加引号
public class Demo01Properties {
    public static void main(String[] args) throws Exception {
        show03();
    }

    private static void show03() throws Exception {
        // 创建Properties集合对象
        Properties prop = new Properties();
        // 使用Properties集合对象中的方法load,读取保存键值对的文件
        prop.load(new FileReader("prop.txt"));
        // 遍历Properties集合
        Set<String> set = prop.stringPropertyNames();
        for (String key : set) {
            String value = prop.getProperty(key);
            System.out.println(key + "=" + value);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值