java基础(四):谈谈java中的IO流

1.字节流

1.1.字节输出流output

1.1.1.数据写入文件中

  经过api查找output。找到不少,其中java.io.OutputStream,OutputStream: 输出字节流的超类。html

  基本特色:java

  一、操做的数据都是字节。编程

  二、定义了输出字节流的基本共性功能。api

  三、输出流中定义都是写write方法。操做字节数组write(byte[]),操做单个字节write(byte)。数组

  子类有规律:全部的子类名称后缀是父类名,前缀名是这个流对象功能bash

  想要操做文件: FileOutputStreamapp

public class FileOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        //需求:将数据写入到文件中。
        //建立存储数据的文件。
        File file = new File("c:\\file.txt");
        //建立一个用于操做文件的字节输出流对象。一建立就必须明确数据存储目的地。
        //输出流目的是文件,会自动建立。若是文件存在,则覆盖。
        FileOutputStream fos = new FileOutputStream(file);
        //调用父类中的write方法。
        byte[] data = "abcde".getBytes();
        fos.write(data);
        //关闭流资源。
        fos.close();
    }
}
复制代码

1.1.2.给文件中续写和换行

  咱们知道直接new FileOutputStream(file)这样建立对象,会覆盖原有的文件,那么咱们想在原有的文件中续写内容怎么办呢?继续查阅FileOutputStream的API。发如今FileOutputStream的构造函数中,能够接受一个boolean类型的值,若是值true,就会在文件末位继续添加ide

public class FileOutputStreamDemo2 {
    public static void main(String[] args) throws Exception {
        File file = new File("c:\\file.txt");
        FileOutputStream fos = new FileOutputStream(file, true);
        String str = "\r\n"+"itcast";
        fos.write(str.getBytes());
        fos.close();
    }
}
复制代码

1.1.3.IO异常的处理

  咱们在开发中应该如何处理这些异常呢?函数

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

        File file = new File("c:\\file.txt");
        //定义FileOutputStream的引用
        FileOutputStream fos = null;
        try {
            //建立FileOutputStream对象
            fos = new FileOutputStream(file);
            //写出数据
            fos.write("abcde".getBytes());

        } catch (IOException e) {
            System.out.println(e.toString() + "----");
        } finally {
            //必定要判断fos是否为null,只有不为null时,才能够关闭资源
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException("");
                }
            }
        }
    }
}
复制代码

1.2.字节输入流Input

1.2.1.读取数据read方法

  经过api查找input。java.io.InputStream。InputStream:字节输入流的超类。学习

  常见功能:

int read():读取一个字节并返回,没有字节返回-1.

int read(byte[]): 读取必定量的字节数,并存储到字节数组中,返回读取到的字节数。

  用于读取文件的字节输入流对象:FileInputStream。

public class FileInputStreamDemo {
    public static void main(String[] args) throws IOException {
        File file = new File("c:\\file.txt");
        //建立一个字节输入流对象,必须明确数据源,其实就是建立字节读取流和数据源相关联。
        FileInputStream fis = new FileInputStream(file);
        //读取数据。使用 read();一次读一个字节。
        int ch = 0;
        while((ch=fis.read())!=-1){
            System.out.println("ch="+(char)ch);
        }
        // 关闭资源。
        fis.close();
    }
}
复制代码

1.2.2.读取数据read(byte[])方法

  在读取文件中的数据时,调用read方法,每次只能读取一个,太麻烦了,因而咱们能够定义数组做为临时的存储容器,这时能够调用重载的read方法,一次能够读取多个字符。

public class FileInputStreamDemo2 {
    public static void main(String[] args) throws IOException {
        /*
         * 演示第二个读取方法, read(byte[]);
         */
        File file = new File("c:\\file.txt");
        // 建立一个字节输入流对象,必须明确数据源,其实就是建立字节读取流和数据源相关联。
        FileInputStream fis = new FileInputStream(file);        
        //建立一个字节数组。
        byte[] buf = new byte[1024];//长度能够定义成1024的整数倍。        
        int len = 0;
        while((len=fis.read(buf))!=-1){
            System.out.println(new String(buf,0,len));
        }
        fis.close();
    }
}
复制代码

2.字符流

  通过前面的学习,咱们基本掌握的文件的读写操做,在操做过程当中字节流能够操做全部数据,但是当咱们操做的文件中有中文字符,而且须要对中文字符作出处理时怎么办呢?

2.1.字节流读取问题

  经过如下程序读取带有中文件的文件。

public class CharStreamDemo {
    public static void main(String[] args) throws IOException {
        //给文件中写中文
        writeCNText();
        //读取文件中的中文
        readCNText();
    }    
    //读取中文
    public static void readCNText() throws IOException {
        FileInputStream fis = new FileInputStream("c:\\cn.txt");
        int ch = 0;
        while((ch = fis.read())!=-1){
            System.out.println(ch);
        }
    }
    //写中文
    public static void writeCNText() throws IOException {
        FileOutputStream fos = new FileOutputStream("c:\\cn.txt");
        fos.write("a传智播客欢迎你".getBytes());
        fos.close();
    }
}
复制代码

  上面程序在读取含有中文的文件时,咱们并无看到具体的中文,而是看到一些数字,这是什么缘由呢?既然看不到中文,那么咱们如何对其中的中文作处理呢?要解决这个问题,咱们必须研究下字符的编码过程。

2.2.编码表

  咱们知道计算机底层数据存储的都是二进制数据,而咱们生活中的各类各样的数据,如何才能和计算机中存储的二进制数据对应起来呢?这时老美他们就把每个字符和一个整数对应起来,就造成了一张编码表,老美他们的编码表就是ASCII表。其中就是各类英文字符对应的编码。

编码表:其实就是生活中字符和计算机二进制的对应关系表。

  • ascii: 一个字节中的7位就能够表示。对应的字节都是正数。0-xxxxxxx

  • iso8859-1:拉丁码表 latin,用了一个字节用的8位。1-xxxxxxx 负数。

  • GB2312:简体中文码表。包含6000-7000中文和符号。用两个字节表示。两个字节都是开头为1 ,两个字节都是负数。

  • GBK:目前最经常使用的中文码表,2万的中文和符号。用两个字节表示,其中的一部分文字,第一个字节开头是1,第二字节开头是0

  • GB18030:最新的中文码表,目前尚未正式使用。

  • unicode:国际标准码表:不管是什么文字,都用两个字节存储。

   Java中的char类型用的就是这个码表。char c = 'a';占两个字节。

   Java中的字符串是按照系统默认码表来解析的。简体中文版 字符串默认的码表是GBK。

  • UTF-8:基于unicode,一个字节就能够存储数据,不要用两个字节存储,并且这个码表更加的标准化,在每个字节头加入了编码信息(后期到api中查找)。

  能识别中文的码表:GBK、UTF-8;正由于识别中文码表不惟一,涉及到了编码解码问题。对于咱们开发而言;常见的编码 GBK UTF-8 ISO8859-1

    文字--->(数字) :编码。

    (数字)--->文字 : 解码。

2.3.FileReader类介绍

  上述程序中咱们读取拥有中文的文件时,使用的字节流在读取,那么咱们读取到的都是一个一个字节。只要把这些字节去查阅对应的编码表,就可以获得与之对应的字符。API中是否给咱们已经提供了读取相应字符的功能流对象呢?

  查阅FileInputStream的API,发现FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader。若是读取字符流,要使用FileReader,FileReader是什么呢?

  打开FileReader的API介绍。用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的,原来FileReader 用于读取字符流。使用FileReader时,了解它的功能,看它所属的体系顶层。

  Reader:读取字符流的抽象超类。

    read():读取单个字符并返回

    read(char[]):将数据读取到数组中,并返回读取的个数。

public class CharStreamDemo {
    public static void main(String[] args) throws IOException {
        //给文件中写中文
        writeCNText();
        //读取文件中的中文
        readCNText();
    }    
    //读取中文
    public static void readCNText() throws IOException {
        FileReader fr = new FileReader("D:\\test\\cn.txt");
        int ch = 0;
        while((ch = fr.read())!=-1){
            //输出的字符对应的编码值
            System.out.println(ch);
            //输出字符自己
            System.out.println((char)ch);
        }
    }
    //写中文
    public static void writeCNText() throws IOException {
        FileOutputStream fos = new FileOutputStream("D:\\test\\cn.txt");
        fos.write("a传智播客欢迎你".getBytes());
        fos.close();
    }
}
复制代码

2.4.FileWriter类介绍

  既然有专门用于读取字符的流对象,那么确定也有写的字符流对象,查阅API,发现有一个Writer类,Writer是写入字符流的抽象类。其中描述了相应的写的动做。

public class FileWriterDemo {
    public static void main(String[] args) throws IOException {
        //演示FileWriter 用于操做文件的便捷类。
        FileWriter fw = new FileWriter("d:\\text\\fw.txt");
        
        fw.write("你好谢谢再见");//这些文字都要先编码。都写入到了流的缓冲区中。
        
        fw.flush();
        
        fw.close();
    }
}
复制代码

2.5.flush()和close()的区别

  flush():将流中的缓冲区缓冲的数据刷新到目的地中,刷新后,流还能够继续使用。

  close():关闭资源,但在关闭前会将缓冲区中的数据先刷新到目的地,不然丢失数据,而后在关闭流。流不可使用。若是写入数据多,必定要一边写一边刷新,最后一次能够不刷新,由close完成刷新并关闭。

3.转换流

  学习完了使用字符流对文件的简单操做后,在学习字符流的时候,其中说若是须要指定编码和缓冲区大小时,能够在字节流的基础上,构造一个InputStreamReader或者OutputStreamWriter,这又是什么意思呢?

3.1.OutputSreamWriter类

  需求:既然识别中文的码表有两个,GBK、UTF-8等,能不能将中文数据按照utf-8的方式进行文件的存储呢?

  还能使用FileWriter吗?不能使用了,由于FileWriter中默认的是GBK。经过FileWriter的api描述,要指定编码表这些值,须要使用OutputStreamWriter

  OutputStreamWriter 是字符流通向字节流的桥梁:可以使用指定的 charset 将要写入流中的字符编码成字节。它的做用的就是,将字符串按照指定的编码表转成字节,在使用字节流将这些字节写出去

public static void writeCN() throws Exception {
        //建立与文件关联的字节输出流对象
        FileOutputStream fos = new FileOutputStream("c:\\cn8.txt");
        //建立能够把字符转成字节的转换流对象,并指定编码
        OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8");
        //调用转换流,把文字写出去,实际上是写到转换流的缓冲区中
        osw.write("你好");//写入缓冲区。
        osw.close();
    }
复制代码

  OutputStreamWriter流对象,它到底如何把字符转成字节输出的呢?

  其实在OutputStreamWriter流中维护本身的缓冲区,当咱们调用OutputStreamWriter对象的write方法时,会拿着字符到指定的码表中进行查询,把查到的字符编码值转成字节数存放到OutputStreamWriter缓冲区中。而后再调用刷新功能,或者关闭流,或者缓冲区存满后会把缓冲区中的字节数据使用字节流写到指定的文件中。

3.2.InputSreamReader类

  查阅InputStreamReader的API介绍,InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集能够由名称指定或显式给定,或者能够接受平台默认的字符集。

public class InputStreamReaderDemo {
    public static void main(String[] args) throws IOException {
        //演示字节转字符流的转换流
        readCN();
    }
    public static void readCN() throws IOException{
        //建立读取文件的字节流对象
        InputStream in = new FileInputStream("c: \\cn8.txt");
        //建立转换流对象 
        //InputStreamReader isr = new InputStreamReader(in);这样建立对象,会用本地默认码表读取,将会发生错误解码的错误
        InputStreamReader isr = new InputStreamReader(in,"utf-8");
        //使用转换流去读字节流中的字节
        int ch = 0;
        while((ch = isr.read())!=-1){
            System.out.println((char)ch);
        }
        //关闭流
        isr.close();
    }
}
复制代码

  注意:在读取指定的编码的文件时,必定要指定编码格式,不然就会发生解码错误,而发生乱码现象

3.3.转换流和子类的区别

  发现有以下继承关系:

    OutputStreamWriter:

      FileWriter:

    InputStreamReader:

      FileReader;

  父类和子类的功能有什么区别呢?

  OutputStreamWriter和InputStreamReader是字符和字节的桥梁:也能够称之为字符转换流。字符转换流原理:字节流+编码表。

  FileWriter和FileReader:做为子类,仅做为操做字符文件的便捷类存在。当操做的字符文件,使用的是默认编码表时能够不用父类,而直接用子类就完成操做了,简化了代码。

  InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默认字符集。

  InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。

  FileReader fr = new FileReader("a.txt");

  这三句代码的功能是同样的,其中第三句最为便捷。

  注意:一旦要指定其余编码时,绝对不能用子类,必须使用字符转换流。何时用子类呢?

  条件:

  一、操做的是文件。二、使用默认编码。3 纯文本

  总结:

  字节--->字符 : 看不懂的--->看的懂的。 须要读。输入流。 InputStreamReader

  字符--->字节 : 看的懂的--->看不懂的。 须要写。输出流。 OutputStreamWriter

4.缓冲流

  在咱们学习字节流与字符流的时候,你们都进行过读取文件中数据的操做,读取数据量大的文件时,读取的速度会很慢,很影响咱们程序的效率,那么, 我想提升速度,怎么办?Java中提升了一套缓冲流,它的存在,可提升IO流的读写速度缓冲流,根据流的分类分类字节缓冲流与字符缓冲流。

4.1.字节缓冲流

  字节缓冲流根据流的方向,共有2个

     写入数据到流中,字节缓冲输出流 BufferedOutputStream

    读取流中的数据,字节缓冲输入流 BufferedInputStream

  它们的内部都包含了一个缓冲区,经过缓冲区读写,就能够提升了IO流的读写速度

4.1.1.字节缓冲输出流BufferedOutputStream

  经过字节缓冲流,进行文件的读写操做 写数据到文件的操做

  构造方法public BufferedOutputStream(OutputStream out)建立一个新的缓冲输出流,以将数据写入指定的底层输出流。

public class BufferedOutputStreamDemo01 {
    public static void main(String[] args) throws IOException {
        
        //写数据到文件的方法
        write();
    }

    /*
     * 写数据到文件的方法
     * 1,建立流
     * 2,写数据
     * 3,关闭流
     */
    private static void write() throws IOException {
        //建立基本的字节输出流
        FileOutputStream fileOut = new FileOutputStream("abc.txt");
        //使用高效的流,把基本的流进行封装,实现速度的提高
        BufferedOutputStream out = new BufferedOutputStream(fileOut);
        //2,写数据
        out.write("hello".getBytes());
        //3,关闭流
        out.close();
    }
}
复制代码

4.1.2.字节缓冲输出流BufferedInputStream

  刚刚咱们学习了输出流实现了向文件中写数据的操做,那么,如今咱们完成读取文件中数据的操做

  构造方法

  public BufferedInputStream(InputStream in)

/*
     * 从文件中读取数据
     * 1,建立缓冲流对象
     * 2,读数据,打印
     * 3,关闭
     */
    private static void read() throws IOException {
        //1,建立缓冲流对象
        FileInputStream fileIn = new FileInputStream("abc.txt");
        //把基本的流包装成高效的流
        BufferedInputStream in = new BufferedInputStream(fileIn);
        //2,读数据
        int ch = -1;
        while ( (ch = in.read()) != -1 ) {
            //打印
            System.out.print((char)ch);
        }
        //3,关闭
        in.close();
    }
复制代码

4.1.3.使用基本的流与高效的流完成复制文件

  咱们一直在说,高效的流速度快并高效,怎么体现呢?须要经过一个复制文件耗时的比较过程,来体验一下高效流带来的快感。

/*
 * 需求:将d:\\test.avi文件进行复制
 *         采用4种方式复制
 *         方式1: 采用基本的流,一次一个字节的方式复制    共耗时 224613毫秒
 *         方式2: 采用基本的流,一个多个字节的方式赋值    共耗时     327毫秒
 *         方式3: 采用高效的流,一次一个字节的方式复制    共耗时    2047毫秒
 *         方式4: 采用高效的流,一个多个字节的方式赋值    共耗时      96毫秒
 * 
 * 数据源: d:\\test.avi
 * 目的地1: d:\\copy1.avi
 * 目的地2: d:\\copy2.avi
 * 目的地3: d:\\copy3.avi
 * 目的地4: d:\\copy4.avi
 * 
 * 实现的步骤:
 *     1,指定数据源
 *     2,指定目的地
 *     3,读数据
 *     4,写数据
 *     5,关闭流
 * 
 */
public class CopyAVI {
    public static void main(String[] args) throws IOException {
        //开始计时
        long start = System.currentTimeMillis();
        //方式1: 采用基本的流,一次一个字节的方式复制
        //method1("d:\\test.avi", "d:\\copy1.avi");
        //方式2: 采用基本的流,一个多个字节的方式赋值
        //method2("d:\\test.avi", "d:\\copy2.avi");
        //方式3: 采用高效的流,一次一个字节的方式复制
        //method3("d:\\test.avi", "d:\\copy3.avi");
        //方式4: 采用高效的流,一个多个字节的方式赋值
        method4("d:\\test.avi", "d:\\copy4.avi");
        
        //结束计时
        long end = System.currentTimeMillis();
        //打印耗时多少毫秒
        System.out.println("共耗时 " +(end - start)+ "毫秒");
    }
    
    //方式4: 采用高效的流,一个多个字节的方式赋值
    private static void method4(String src, String dest) throws IOException {
        //1,指定数据源
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
         //2,指定目的地
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
         //3,读数据
        byte[] buffer = new byte[1024];
        int len = -1;
        while ( (len = in.read(buffer)) != -1) {
            //4,写数据
            out.write(buffer, 0, len);
        }
         //5,关闭流
        in.close();
        out.close();
    }

    //方式3: 采用高效的流,一次一个字节的方式复制
    private static void method3(String src, String dest) throws IOException {
        //1,指定数据源
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
         //2,指定目的地
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
         //3,读数据
        int ch = -1;
        while ((ch=in.read()) != -1) {
            //4,写数据
            out.write(ch);    
        }        
         //5,关闭流
        in.close();
        out.close();
    }

    //方式2: 采用基本的流,一个多个字节的方式赋值
    private static void method2(String src, String dest) throws IOException {
        //1,指定数据源
        FileInputStream in = new FileInputStream(src);
        //2,指定目的地
        FileOutputStream out = new FileOutputStream(dest);
        //3,读数据
        byte[] buffer = new byte[1024];
        int len = -1;
        while ( (len=in.read(buffer)) != -1) {
            //4,写数据
            out.write(buffer, 0, len);
        }
        //5,关闭流
        in.close();
        out.close();
    }

    //方式1: 采用基本的流,一次一个字节的方式复制
    private static void method1(String src, String dest) throws IOException {
        //1,指定数据源
        FileInputStream in = new FileInputStream(src);
        //2,指定目的地
        FileOutputStream out = new FileOutputStream(dest);
        //3,读数据
        int ch = -1;
        while (( ch=in.read()) != -1) {
            //4,写数据
            out.write(ch);
        }
        //5,关闭流
        in.close();
        out.close();
    }
}
复制代码

4.2.字符缓冲流

  字符缓冲输入流 BufferedReader

  字符缓冲输出流 BufferedWriter

  完成文本数据的高效的写入与读取的操做

4.2.1.字符缓冲输出流BufferedWriter

  将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

  方法:void newLine() 根据当前的系统,写入一个换行符

/*
 * BufferedWriter 字符缓冲输出流
 * 方法
 *     public void newLine()写入一个行分隔符
 * 
 * 需求: 经过缓冲输出流写入数据到文件
 * 分析:
 *     1,建立流对象
 *     2,写数据
 *     3,关闭流
 * 
 */
public class BufferedWriterDemo {
    public static void main(String[] args) throws IOException {
        //建立流
        //基本字符输出流
        FileWriter fileOut = new FileWriter("file.txt");
        //把基本的流进行包装
        BufferedWriter out = new BufferedWriter(fileOut);
        //2,写数据
        for (int i=0; i<5; i++) {
            out.write("hello");
            out.newLine();
        }
        //3,关闭流
        out.close();
    }
}
复制代码

4.2.2.字符缓冲输入流BufferedReader

  从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

  方法public String readLine() 读取一个文本行,包含该行内容的字符串,不包含任何行终止符,若是已到达流末尾,则返回 null

/*
 * BufferedReader 字符缓冲输入流
 * 
 * 方法:
 *     String readLine() 
 * 需求:从文件中读取数据,并显示数据
 */
public class BufferedReaderDemo {
    public static void main(String[] args) throws IOException {
        //1,建立流
        BufferedReader in = new BufferedReader(new FileReader("file.txt"));
        //2,读数据
        //一次一个字符
        //一次一个字符数组
        //一次读取文本中一行的字符串内容
        String line = null;
        while( (line = in.readLine()) != null ){
            System.out.println(line);
        }
        
        //3,关闭流
        in.close();
    }
}
复制代码

4.2.3.使用字符缓冲流完成文本文件的复制

  刚刚咱们学习完了缓冲流,如今咱们就使用字符缓冲流的特有功能,完成文本文件的复制

/*
 * 采用高效的字符缓冲流,完成文本文件的赋值
 * 
 * 数据源: file.txt
 * 目的地: copyFile.txt
 * 
 * 分析:
 *     1,指定数据源, 是数据源中读数据,采用输入流
 *     2,指定目的地,是把数据写入目的地,采用输出流
 *     3,读数据
 *     4,写数据
 *     5,关闭流
 */
public class CopyTextFile {
    public static void main(String[] args) throws IOException {
        //1,指定数据源, 是数据源中读数据,采用输入流
        BufferedReader in = new BufferedReader(new FileReader("file.txt"));
        //2,指定目的地,是把数据写入目的地,采用输出流
        BufferedWriter out = new BufferedWriter(new FileWriter("copyFile.txt"));
        //3,读数据
        String line = null;
        while ( (line = in.readLine()) != null ) {
            //4,写数据
            out.write(line);
            //写入换行符号
            out.newLine();
        }
        //5,关闭流
        out.close();
        in.close();
    }
}
复制代码

5.Properties类

5.1.Properties类介绍

  Properties特色:

    一、Hashtable的子类,map集合中的方法均可以用。

    二、该集合没有泛型。键值都是字符串。

    三、它是一个能够持久化的属性集。键值能够存储到集合中,也能够存储到持久化的设备(硬盘、U盘、光盘)上。键值的来源也能够是持久化的设备。

    四、有和流技术相结合的方法。

      a.load(InputStream) 把指定流所对应的文件中的数据,读取出来,保存到Propertie集合中

      b. load(Reader)

      c. store(OutputStream,commonts)把集合中的数据,保存到指定的流所对应的文件中,参数commonts表明对描述信息

      d.stroe(Writer,comments);

/*
 * 
 * Properties集合,它是惟一一个能与IO流交互的集合
 * 
 * 需求:向Properties集合中添加元素,并遍历
 * 
 * 方法:
 * public Object setProperty(String key, String value)调用 Hashtable 的方法 put。
 * public Set<String> stringPropertyNames()返回此属性列表中的键集,
 * public String getProperty(String key)用指定的键在此属性列表中搜索属性
 */
public class PropertiesDemo01 {
    public static void main(String[] args) {
        //建立集合对象
        Properties prop = new Properties();
        //添加元素到集合
        //prop.put(key, value);
        prop.setProperty("周迅", "张学友");
        prop.setProperty("李小璐", "贾乃亮");
        prop.setProperty("杨幂", "刘恺威");
        
        //System.out.println(prop);//测试的使用
        //遍历集合
        Set<String> keys = prop.stringPropertyNames();
        for (String key : keys) {
            //经过键 找值
            //prop.get(key)
            String value = prop.getProperty(key);
            System.out.println(key+"==" +value);
        }
    }
}
复制代码

将配置文件中的数据存储到文件中

/**
 * 需求:使用Properties集合,完成把集合内容存储到IO流所对应文件中的操做
 * 
 * 分析:
 *     1,建立Properties集合
 *     2,添加元素到集合
 *     3,建立流
 *     4,把集合中的数据存储到流所对应的文件中
 *        store(OutputStream,commonts)把集合中的数据,保存到指定的流所对应的文件中,参数commonts表明对描述信息
 *        stroe(Writer,comments);
 *     5,关闭流
 */
public class PropertiesDemo02 {
    public static void main(String[] args) throws IOException {
        //1,建立Properties集合
        Properties prop = new Properties();
        //2,添加元素到集合
        prop.setProperty("周迅", "张学友");
        prop.setProperty("李小璐", "贾乃亮");
        prop.setProperty("杨幂", "刘恺威");
        
        //3,建立流
        FileWriter out = new FileWriter("prop.properties");
        //4,把集合中的数据存储到流所对应的文件中
        prop.store(out, "save data");
        //5,关闭流
        out.close();
    }
}
复制代码

读取配置文件中的数据,同时更新数据,并保存

/*
 * 需求:从属性集文件prop.properties 中取出数据,保存到集合中
 * 分析:
 *     1,建立集合
 *     2,建立流对象
 *     3,把流所对应文件中的数据 读取到集合中
 *        load(InputStream)  把指定流所对应的文件中的数据,读取出来,保存到Propertie集合中
        load(Reader)  
 *     4,关闭流
 *     5,显示集合中的数据
 */
public class PropertiesDemo03 {
    public static void main(String[] args) throws IOException {
        //1,建立集合
        Properties prop = new Properties();
        //2,建立流对象
        FileInputStream in = new FileInputStream("prop.properties");
//FileReader in = new FileReader("prop.properties");
        //3,把流所对应文件中的数据 读取到集合中
        prop.load(in);
        //4,关闭流
        in.close();
        //5,显示集合中的数据
        System.out.println(prop);
        
    }
复制代码

注意:使用字符流FileReader就能够完成文件中文的读取操做了

6.序列化流与烦序列化流

6.1.对象序列化流

  用于从流中读取对象的操做流 ObjectInputStream 称为 反序列化流

  用于向流中写入对象的操做流 ObjectOutputStream 称为 序列化流

  特色:用于操做对象。

  解决问题:能够将对象进行序列化和反序列化

  注意:对象序列化必定要实现Serializable接口。为了给类定义一个serialVersionUID。

  功能:

   ObjectInputStream readObject()

   ObjectOutputStream writeObject()

public class ObjectStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        /*
         * 将一个对象存储到持久化(硬盘)的设备上。
         */
        writeObj();//对象的序列化。
    }
    public static void writeObj() throws IOException {
        //1,明确存储对象的文件。
        FileOutputStream fos = new FileOutputStream("tempfile\\obj.object");
        //2,给操做文件对象加入写入对象功能。
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        //3,调用了写入对象的方法。
        oos.writeObject(new Person("wangcai",20));
        //关闭资源。
        oos.close();
    }
}
复制代码

6.2.对象反序列化流

  当把一个对象持久化存储起来以后,须要使用反序列化技术获取存储起来的对象。使用此ObjectInputStream对象就能够完成反序列化动做

public class ObjectStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        readObj();//对象的反序列化。
    }
    public static void readObj() throws IOException, ClassNotFoundException {
        
        //1,定义流对象关联存储了对象文件。
        FileInputStream fis = new FileInputStream("tempfile\\obj.object");
        
        //2,创建用于读取对象的功能对象。
        ObjectInputStream ois = new ObjectInputStream(fis);
        
        Person obj = (Person)ois.readObject();
        
        System.out.println(obj.toString());
        
    }
}
复制代码

6.3.序列化接口

  当一个对象要能被序列化,这个对象所属的类必须实现Serializable接口。不然会发生异常NotSerializableException异常。

  同时当反序列化对象时,若是对象所属的class文件在序列化以后进行的修改,那么进行反序列化也会发生异常InvalidClassException。发生这个异常的缘由以下:

     该类的序列版本号与从流中读取的类描述符的版本号不匹配

     该类包含未知数据类型

     该类没有可访问的无参数构造方法

  Serializable标记接口。该接口给须要序列化的类,提供了一个序列版本号。serialVersionUID. 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

public class Person implements Serializable {

    //给类显示声明一个序列版本号。
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    public Person() {
        super();
        
    }
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}
复制代码

7.总结

  • 字节流

   字节输入流 InputStream

    FileInputStream 操做文件的字节输入流

    BufferedInputStream高效的字节输入流

     ObjectInputStream 反序列化流(操做对象的字节输入流)

   字节输出流 OutputStram

     FileOutputStream 操做文件的字节输出流

    BufferedOutputStream 高效的字节输出流

     ObjectOuputStream 序列化流(操做对象的字节输出流)

  • 字符流

   字符输入流 Reader

    FileReader 操做文件的字符输入流

     BufferedReader 高效的字符输入流

     InputStreamReader 输入操做的转换流(把字节流封装成字符流)

   字符输出流 Writer

    FileWriter 操做文件的字符输出流

     BufferedWriter 高效的字符输出流

     OutputStreamWriter 输出操做的转换流(把字节流封装成字符流)

              将字符流转换成字节流去存储

  • 方法:

  读数据方法:

    read() 一次读一个字节或字符的方法

    read(byte[] char[]) 一次读一个数组数据的方法

    readLine() 一次读一行字符串的方法(BufferedReader类特有方法)

     readObject() 从流中读取对象(ObjectInputStream特有方法)

  写数据方法:

    write(int) 一次写一个字节或字符到文件中

    write(byte[] char[]) 一次写一个数组数据到文件中

     write(String) 一次写一个字符串内容到文件中

     writeObject(Object ) 写对象到流中(ObjectOutputStream类特有方法)

    newLine() 写一个换行符号(BufferedWriter类特有方法)

  • 向文件中写入数据的过程

  1,建立输出流对象

  2,写数据到文件

  3,关闭输出流

  • 从文件中读数据的过程

  1, 建立输入流对象

  2, 从文件中读数据

  3, 关闭输入流

  • 文件复制的过程

  1, 建立输入流(数据源)

  2, 建立输出流(目的地)

  3, 从输入流中读数据

  4, 经过输出流,把数据写入目的地

  5, 关闭流

  • Properties:Map集合的一种,它是Hashtable集合的子集合,它键与值都是String类型,它是惟一能与IO流结合使用的集合

  方法

  load( InputStream in ) 从流所对应的文件中,读数据到集合中

   load( Reader in ) 从流所对应的文件中,读数据到集合中

  store( OutputStream out , String message ) 把集合中的数据,写入到流所对应的文件中

  store( Writer out , String message) 把集合中的数据,写入到流所对应的文件中

实现文件内容的自动追加

构造方法

   FileOutputStream(File file, boolean append)

   FileOutputStream(String fileName, boolean append)

   FileWriter(File, boolean append)

   FileWriter(String fileName, boolean append)

参考:

java编程思想

黑马教学视频

www.cnblogs.com/dz-boss/p/1…

相关文章
相关标签/搜索