IO流之数据输入输出流+内存操作流+打印流+随机访问流+序列化流和反序列化流+Properties+SequenceInputStream

一.数据输入输出流

  		数据输入流:
        DataInputStream
        数据输出流:
        DataOutputStream
        这对流的特点是能够读写基本数据类型
           以Stream结尾的 一般都是字节流
package org.westos.demo;

import java.io.*;

public class MyTest2 {
    public static void main(String[] args) throws IOException {
        /*数据输入流:
        DataInputStream
        数据输出流:
        DataOutputStream
        这对流的特点是能够读写基本数据类型
           以Stream结尾的 一般都是字节流*/
        DataOutputStream out = new DataOutputStream(new FileOutputStream("a.txt"));
        out.writeInt(100);
        out.writeBoolean(true);
        out.writeChar('a');

        out.writeUTF("aaa");
        System.out.println("=============");

        //读和写的顺序要保持一致
        DataInputStream in = new DataInputStream(new FileInputStream("a.txt"));
        int num1 = in.readInt();
        System.out.println(num1);

        boolean b = in.readBoolean();
        System.out.println(b);

        char c = in.readChar();
        System.out.println(c);

        String s = in.readUTF();
        System.out.println(s);
    }
}

二.内存操作流

A:内存操作流的概述
		a:操作字节数组
			ByteArrayOutputStream
			ByteArrayInputStream
			此流关闭无效,所以无需关闭
		b:操作字符数组
			CharArrayWrite
			CharArrayReader
		c:操作字符串
			StringWriter
			StringReader	

1.ByteArrayOutputStream和ByteArrayInputStream

(1)  ByteArrayOutputStream此类实现了一个输出流,其中的数据被写入一个 byte 数组。
        缓冲区会随着数据的不断写入而自动增长。
        可使用 toByteArray () 和 toString () 获取数据。
        
         ByteArrayOutputStream()
        创建一个新的 byte 数组输出流
		不会直接去关联文件,只是在内存中进行数据的读写
		
        关闭 ByteArrayOutputStream 无效
(2)ByteArrayInputStream(byte[] buf)
        创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。
package org.westos.demo;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class MyTest3 {
    public static void main(String[] args) throws IOException {
        /*		a:操作字节数组
			ByteArrayOutputStream
			ByteArrayInputStream
			此流关闭无效,所以无需关闭*/
           /*
           ByteArrayOutputStream此类实现了一个输出流,其中的数据被写入一个 byte 数组。
        缓冲区会随着数据的不断写入而自动增长。
        可使用 toByteArray () 和 toString () 获取数据。

        关闭 ByteArrayOutputStream 无效。*/
       /* ByteArrayOutputStream()
        创建一个新的 byte 数组输出流*/

        //不会直接去关联文件,只是在内存中进行数据的读写
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        //把字节数组,写入到ByteArrayOutputStream自己所维护的那个字节数组中去
        out.write("我爱Java".getBytes());
        out.write("老鼠爱大米".getBytes());
        out.write("本伟卢氏".getBytes());

        //取出ByteArrayOutputStream 他所维护的那个字节数组中的字节数据
        byte[] bytes = out.toByteArray();
        String s = new String(bytes);
        System.out.println(s);
        String string = out.toString();
        System.out.println(string);
        System.out.println("======================");

         /* ByteArrayInputStream(byte[] buf)
        创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。*/
        ByteArrayOutputStream out2 = new ByteArrayOutputStream();
        out2.write("我爱Java".getBytes());
        out2.write("老鼠爱大米".getBytes());
        out2.write("本伟卢氏".getBytes());

        //取出ByteArrayOutputStream 他所维护的那个字节数组中的字节数据
        byte[] allByte  = out2.toByteArray();
        ByteArrayInputStream in = new ByteArrayInputStream(allByte);

        byte[] epmtyBytes  = new byte[1024*8];

        int len = in.read(epmtyBytes);
        String s1 = new String(epmtyBytes, 0, len);
        System.out.println(s1);

        /*ByteArrayInputStream in = new ByteArrayInputStream(bytes1);

        int len = in.read(bytes1);
        String s1 = new String(bytes1,0,len);
        System.out.println(s1);*/

        in.close();
        out.close();
        out2.close();

    }
}

案例:合并两首歌

方式一:

package org.westos.demo;

import java.io.*;
import java.util.ArrayList;

public class MyTest4 {
    public static void main(String[] args) throws IOException {
        //合并两首歌
        FileInputStream in1 = new FileInputStream("许巍 - 蓝莲花.mp3");
        FileInputStream in2 = new FileInputStream("陈一发儿01 - 童话镇.mp3");

        ArrayList<FileInputStream> list = new ArrayList<>();
        list.add(in1);
        list.add(in2);

        ByteArrayOutputStream out = new ByteArrayOutputStream();

        int len=0;
        byte[] bytes = new byte[1024*8];

        for (FileInputStream in : list) {
            while ((len=in.read(bytes))!=-1){
                out.write(bytes,0,len);

            }
            in.close();
        }

        //取出两首歌的字节数据
        byte[] allByte = out.toByteArray();

        //把两首歌的字节数据写入到一个文件中
        //取出ByteArrayOutputStream 他所维护的那个字节数组中的字节数据
        ByteArrayInputStream bis = new ByteArrayInputStream(allByte);

        FileOutputStream out2 = new FileOutputStream("C:\\Users\\user\\Desktop\\歌曲大连唱.mp3");

        int len2=0;
        byte[] bytes2 = new byte[1024*8];
        while ((len2=bis.read(bytes2))!=-1){
            out2.write(bytes2,0,len2);
        }
            out2.close();
    }
}

方式二:

package org.westos.demo;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

public class MyTest5 {
    public static void main(String[] args)  throws IOException {
        //合并多个文件,没有必要使用内存操作流
        //合并两首歌
        FileInputStream in1 = new FileInputStream("许巍 - 蓝莲花.mp3");
        FileInputStream in2 = new FileInputStream("陈一发儿01 - 童话镇.mp3");

        ArrayList<FileInputStream> list = new ArrayList<>();
        list.add(in1);
        list.add(in2);

        FileOutputStream out = new FileOutputStream("C:\\Users\\user\\Desktop\\demo\\歌曲大联唱");

        int len=0;
        byte[] bytes = new byte[1024*8];

        for (FileInputStream in : list) {
            while ((len=in.read(bytes))!=-1){
                out.write(bytes,0,len);
            }
            in.close();
        }
        out.close();
    }
}

2.CharArrayWrite和CharArrayReader

操作字符数组
        CharArrayWrite  他维护的缓冲区是一个字符数组
        CharArrayReader
package org.westos.demo2;

import java.io.CharArrayWriter;
import java.io.IOException;

public class MyTest {
    public static void main(String[] args) throws IOException {
        /*操作字符数组
        CharArrayWriter  他维护的缓冲区是一个字符数组
        CharArrayReader*/
        CharArrayWriter writer = new CharArrayWriter();
        String str = "好好学习";
        String str2 = "天天向上";
        String str3 = "爱生活";
        String str4 = "爱Java";

        //把字符串,写入到CharArrayWrite维护的字符数组中去
        writer.write(str);
        writer.write(str2);
        writer.write(str3);
        writer.write(str4);

        //取出CharArrayWrite所维护的字符数组
        char[] chars = writer.toCharArray();
        System.out.println(chars);

        String s = new String(chars);
        System.out.println(s);

        System.out.println(writer.toString());


    }
}

3.StringWriter和StringReader

 操作字符串
        StringWriter  他底层用的是SStringBuffer 来充当缓冲区
        StringReader
package org.westos.demo2;

import java.io.StringWriter;

public class MyTest2 {
    public static void main(String[] args) {
        /* 操作字符串
        StringWriter  他底层用的是StringBuffer 来充当缓冲区
        StringReader*/
        StringWriter writer = new StringWriter();
        writer.write("aaa");
        writer.write("aaa");
        writer.write("aaa");
        writer.write("aaa");
        System.out.println(writer);
        System.out.println(writer.toString());
    }
}

三.打印流

1.概述

A:打印流的概述
	分类:
		字节流打印流
		字符打印流
	B:打印流的特点:单独存在,只能写不能读
		a: 打印流只能操作目的地,不能操作数据源(不能进行读取数据)
		- b: 可以操作任意数据类型的数据 调用print() 方法可以写任意数据类型
	
	- c: 如果我们启用自动刷新,那么在调用println、printf 或 format 方法中的一个方法的时候,会完成自动刷新
	  		/**
	  		通过以下构造创建对象 能够启动自动刷新  然后调用println、printf 或 format 方法中的一个方法的时候,会完成自动刷新
	  	 * public PrintWriter(OutputStream out,  boolean autoFlush)	 启动 自动刷新
	  	 * public PrintWriter(Writer out,  boolean autoFlush)		启动自动刷新
	  	 */
	
	- d: 这个流可以直接对文件进行操作(可以直接操作文件的流: 就是构造方法的参数可以传递文件或者文件路径)

2.字符打印流

PrintWriter

构造方法:
		PrintWriter(File file)
        使用指定文件创建不具有自动行刷新的新 PrintWriter。

        PrintWriter(String fileName)
          创建具有指定文件名称且不带自动行刷新的新 PrintWriter。

		PrintWriter(OutputStream out, boolean autoFlush)
        通过现有的 OutputStream 创建新的 PrintWriter。参数2:true开启自动刷新
        PrintWriter(Writer out, boolean autoFlush)
        创建新 PrintWriter。参数2:true开启自动刷新
        
         如果启用了自动刷新,则只有在调用 println、printf 或 format
    的其中一个方法时才可能完成此操作,而不是每当正好输出换行符时才完成。
package org.westos.demo2;

import java.io.IOException;
import java.io.PrintWriter;

public class MyTest3 {
    public static void main(String[] args) throws IOException {
        //打印流,单独存在,只能写不能读
        //字节打印流,字符打印流

        /*字符打印流:

        PrintWriter
        构造方法:
		PrintWriter(File file)
        使用指定文件创建不具有自动行刷新的新 PrintWriter。

        PrintWriter(String fileName)
        创建具有指定文件名称且不带自动行刷新的新 PrintWriter。
        * */
        PrintWriter writer = new PrintWriter("b.txt");
        writer.write("本伟卢氏");
        writer.write("\r\n");

        writer.write(100);
        writer.write("\r\n");

        writer.write(91);
        writer.write("\r\n");

        //写入并换行
        writer.println(100);
        writer.println(65);
        writer.println(65);

        writer.print(true);
        writer.write("\r\n");
        writer.flush();

    }
}

package org.westos.demo2;

import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class MyTest4 {
    public static void main(String[] args) throws IOException {
           /*  PrintWriter(OutputStream out, boolean autoFlush)
                通过现有的 OutputStream 创建新的 PrintWriter。
               PrintWriter(Writer out, boolean autoFlush)
                创建新 PrintWriter。*/
            //参数2:true开启自动刷新
            /*   如果启用了自动刷新,则只有在调用 println、printf 或 format
            的其中一个方法时才可能完成此操作,而不是每当正好输出换行符时才完成。*/

        PrintWriter writer = new PrintWriter(new FileWriter("c.txt"),true);
        writer.write("1111");
        writer.write("2222");
        writer.flush();

        writer.printf("3333");
        writer.println("aaaa");
        writer.println("aaaa");
        writer.println("aaaa");
        writer.println("aaaa");
        writer.close();

    }
}

3.字节打印流

PrintStream 字节打印流 单个的,只能输出数据。
	构造方法:
		  	 PrintStream(File file)
          创建具有指定文件且不带自动行刷新的新打印流。
		  	PrintStream(File file, String csn)
          创建具有指定文件名称和字符集且不带自动行刷新的新打印流。
  			PrintStream(OutputStream out)
          创建新的打印流。

         	 PrintStream(String fileName)
          创建具有指定文件名称且不带自动行刷新的新打印流。
			PrintStream(String fileName, String csn)
          创建具有指定文件名称和字符集且不带自动行刷新的新打印流。
package org.westos.demo2;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;

public class MyTest5 {
    public static void main(String[] args) throws IOException {
        /*   PrintStream(File file)
          创建具有指定文件且不带自动行刷新的新打印流。
            PrintStream(File file, String csn)
          创建具有指定文件名称和字符集且不带自动行刷新的新打印流。
            PrintStream(OutputStream out)
          创建新的打印流。

          PrintStream(String fileName)
          创建具有指定文件名称且不带自动行刷新的新打印流。
            PrintStream(String fileName, String csn)
          创建具有指定文件名称和字符集且不带自动行刷新的新打印流。*/

        //new一个字节打印流,与传入的文件相关联,调用println()方法就是写入数据到关联的文件中
        PrintStream stream = new PrintStream("d.txt");

        stream.println(100);
        stream.print(true);
        stream.print(true);
        stream.print(true);
        stream.println("aaaa");
        stream.flush();
        stream.close();
        System.out.println("=======================");

        //我们通过System类中的静态变量in 可以获取出一个PrintStream字节打印流 调用输出的方法时输出的目的地是屏幕
        // System类的属性 out标准”输出流。此流已打开并准备接受输出数据。通常,此流对应于显示器输出

        InputStream in = System.in;

        PrintStream out = System.out;

        out.write("111".getBytes());
        out.println(100);
        out.println(200);
        out.println(200);
        out.println(200);
    }
}

案例:使用打印流来复制文件

package org.westos.demo2;

import java.io.*;

public class MyTest6 {
    public static void main(String[] args) throws IOException {
        //使用打印流来复制文本文件
        PrintWriter writer = new PrintWriter(new FileWriter("MyTest2.java"));

        BufferedReader reader = new BufferedReader(new FileReader("MyTest.java"));

        String s=null;

        while((s=reader.readLine())!=null){
            writer.println(s);
        }
        reader.close();
        writer.close();
    }
}

四.标准输入输出流

1.概述

A:标准输入输出流概述
		在System这个类中存在两个静态的成员变量:
		
	- public static final InputStream in: 标准输入流, 对应的设备是键盘
	此流已打开并准备提供输入数据。通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。
	
	- public static final PrintStream out: 标准输出流 , 对应的设备就是显示器
	  	System.in的类型是InputStream.
	  	System.out的类型是PrintStream是OutputStream的孙子类FilterOutputStream 的子类.
package org.westos.demo3;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Scanner;

public class MyTest {
    public static void main(String[] args) throws IOException {
        /* System类中的静态成员变量:
        public static final InputStream in: 标准输入流, 对应的设备是键盘
	此流已打开并准备提供输入数据。通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。*/

        /*Scanner(File source)
        构造一个新的 Scanner,它生成的值是从指定文件扫描的。
        Scanner(InputStream source)
        构造一个新的 Scanner,它生成的值是从指定的输入流扫描的。*/
        //Scanner scanner = new Scanner(System.in);
        //Scanner类关联文件

        Scanner sc = new Scanner(new File("MyTest.java"));
        while (sc.hasNextLine()){
            String s = sc.nextLine();
            System.out.println(s);
        }
    }
}

案例:用Scanner和PrintWriter 配合来复制文件

package org.westos.demo3;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;

public class MyTest2 {
    public static void main(String[] args) throws IOException {
        //用Scanner和PrintWriter 配合来复制文件
        //Scanner关联文件
        Scanner sc = new Scanner(new File("MyTest.java"));

        PrintWriter writer = new PrintWriter("MyTest3.java");
        while (sc.hasNextLine()) {
            String s = sc.nextLine();
            writer.println(s);
        }
        sc.close();
        writer.close();
    }
}

2.键盘录入的两种方式

package org.westos.demo3;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;

public class MyTest3 {
    public static void main(String[] args) throws IOException {
       /*
       键盘录入的二种方式
       in
       public static final InputStream in“标准”输入流。
        此流已打开并准备提供输入数据。通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。
        Scanner scanner = new Scanner(System.in);
        */

        //in返回的是InputStream类型

        //键盘录入的第一种方式
        //Scanner sc = new Scanner(System.in);

        //从键盘上读取数据,键盘录入的第二种方式
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        while (true){
            System.out.println("请输入数据");
            String s = reader.readLine();
            System.out.println(s);
            //定义一个结束标记
            if (s.equals("再见")){
                break;
            }
        }

    }
}

3.注意事项

 获取System下的in成员变量
        InputStream in = System.in ;

          in是一个字节输入流对象,那么我们就可以通过这个字节输入流对象进行读取键盘录入的数据.
          那么我们既然要读取数据,之前我们讲解了两种读取数据的方式:
          	 1. 一次读取一个字节
          	 2. 一次读取一个字节数组
          那么我们在这个地方使用那种读取方式. 经过分析,这两种读取方式都不太合适.因为数据是客户通过键盘录入
          进来的,而我们希望直接读取一行数据. 而既然要读取一行数据,那么我们就需要使用readLine方法,而这个方法
          是属于BufferedReader的方法,而我们就需要创建一个BufferedReader对象进行读取数据.而我们这in有属于
          字节流,而创建BufferedReader对象的时候需要一个字符流,而我们就需要将这个字节流转换成字符流,那么既然
          要对其进行转换,那么就需要使用转换流. 需要使用InputStreamReader

五.随机访问流

1.概述

A:随机访问流概述
		RandomAccessFile概述 最大特点 能读能写
		RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能。
		支持对随机访问文件的读取和写入。
	
		 RandomAccessFile的父类是Object , 这个流对象可以用来读取数据也可以用来写数据.可以操作任意数据类型的数据.
	我们可以通过getFilePointer方法获取文件指针,并且可以通过seek方法设置文件指针
	
  RandomAccessFile概述 最大特点 能读能写而且有一个文件指针,可以控制指针的位置。
        此类的实例支持对随机访问文件的读取和写入。
        随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。
        存在指向该隐含数组的光标或索引,称为文件指针;
        输入操作从文件指针开始读取字节,
        并随着对字节的读取而前移此文件指针。

构造方法:
RandomAccessFile(String name, String mode)
        创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。
package org.westos.demo4;

import java.io.IOException;
import java.io.RandomAccessFile;

public class MyTest {
    public static void main(String[] args) throws IOException {
        //随机访问流
        // RandomAccessFile概述 最大特点 能读能写而且有一个文件指针,可以控制指针的位置。
      /*  此类的实例支持对随机访问文件的读取和写入。
        随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。
        存在指向该隐含数组的光标或索引,称为文件指针;
        输入操作从文件指针开始读取字节,
        并随着对字节的读取而前移此文件指针。*/

        /*RandomAccessFile(String name, String mode)
        创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。*/

        //rw表示可读可写
        RandomAccessFile file = new RandomAccessFile("e.txt","rw");
        file.writeInt(200);
        file.writeBoolean(true);
        file.writeChar('a');

        //写入中文,注意会多写两个字节
        file.writeUTF("本伟卢氏");
        System.out.println("===================");

        //读取文件,注意读写顺序要一致,怎么写的就怎么读
        RandomAccessFile file2 = new RandomAccessFile("e.txt", "rw");
        System.out.println(file2.readInt());

        long filePointer = file2.getFilePointer();
        System.out.println("文件指针的位置"+filePointer);//4

        System.out.println(file2.readBoolean());
        filePointer = file2.getFilePointer();
        System.out.println("文件指针的位置"+filePointer);//5

        System.out.println(file2.readChar());
        filePointer = file2.getFilePointer();
        System.out.println("文件指针的位置"+filePointer);//7

        System.out.println(file2.readUTF());
        filePointer = file2.getFilePointer();
        System.out.println("文件指针的位置"+filePointer);//21
         file.close();
        file2.close();
    }
}

案例:复制文件,可以暂停继续

package org.westos.demo4;

import jdk.nashorn.internal.runtime.ECMAException;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;

public class MyTest2 {
    public static void main(String[] args) throws IOException {
        //复制文件,可以暂停继续
        //下载到一半时,暂停下载,明天继续下载
        RandomAccessFile file = new RandomAccessFile("陈一发儿01 - 童话镇.mp3","rw");

        File file1 = new File("C:\\Users\\user\\Desktop\\陈一发儿02 - 童话镇.mp3");

        RandomAccessFile file2 = new RandomAccessFile(file1, "rw");

        //严谨性判断,如果上次没复制完的文件,不存在了,就从头开始复制
      /*  if(!file1.exists()||fil1.length()<上次记录的字节数){
            //把文件指针设置为0 从头开始读
            file.seek(0);
            //把文件指针设置为0 从头开始写
            file2.seek(0);
        }else{
            //从配置文件中读取上次断开的位置
            file.seek(3001);
            //从配置文件中读取上次断开的位置
            fiel2.seek(3301);
        }*/

        int len=0;
        int i=0;
        try {
            while ((len=file.read())!=-1){
               /*模拟一个异常,或模拟用户暂停
              if(i++>3000){
                    System.out.println(1/0);
                }*/
                file2.write(len);
            }
        }catch (Exception e){
            //当复制或下载文件过程当中遇到了异常或用户手动暂停,我们zt");
            writer.println(filePointer);
            writer.flush();
            writer.close();
            e.printStackTrace();
        }

    }
}

作业:把一个文件复制三份

方式1

package org.westos.demo;

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

public class MyTest {
    public static void main(String[] args) throws IOException {
        //如何将一个文件复制三份


        for (int i = 1; i <= 3; i++) {
            FileInputStream in = new FileInputStream("Student.java");
            long l = System.currentTimeMillis();
            String s = String.valueOf(l);

            FileOutputStream out = new FileOutputStream(s);
            int len=0;
            byte[] bytes = new byte[1024 * 8];
            while ((len=in.read(bytes))!=-1){
                out.write(bytes,0,len);
                out.flush();
            }
            
            out.close();
            in.close();
        }

    }
}

六.序列化和反序列化流

1.概述

A:序列化流的概述
		所谓的序列化:就是把对象通过流的方式存储到文件中.注意:此对象 要重写Serializable 接口才能被序列化
		反序列化:就是把文件中存储的对象以流的方式还原成对象
		序列化流:	ObjectOutputStream
		反序列化流:	ObjectInputStream
		
 序列化和反序列化
        序列化:将Java对象保存到文件中
        反序列化:将文件中的对象,读取回内存。

        这对流能够对Java对象进行读写
        序列化流:
        ObjectOutputStream
        反序列化流:
        ObjectInputStream
		 
		 像这样一个接口中如果没有方法,那么这样的接口我们将其称之为标记接口(用来给类打标记的,相当于猪肉身上盖个章)
	 一个对象可以被序列化的前提是这个对象对应的类必须实现Serializable接口
	 
	   ObjectOutputStream(OutputStream out)
        创建写入指定 OutputStream 的 ObjectOutputStream。
package org.westos.demo;

import java.io.*;

public class MyTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
       /* 序列化和反序列化
        序列化:将Java对象保存到文件中
        反序列化:将文件中的对象,读取回内存。
        此对象 要重写Serializable 接口才能被序列化

        这对流能够对Java对象进行读写
        序列化流:
        ObjectOutputStream
        反序列化流:
        ObjectInputStream

        构造方法:
          ObjectOutputStream(OutputStream out)
        创建写入指定 OutputStream 的 ObjectOutputStream。*/
        Student student = new Student("本伟", 33,'男');
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("student.txt"));

        //把Java对象写到文件中
        //1.当我们去序列化一个Java对象时,要求我们这个对象所对应的类,必须实现一个序列化接口Serializable
        out.writeObject(student);
        System.out.println("=================");
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("student.txt"));
        Object object = in.readObject();
        Student s= (Student) object;
        System.out.println(s.getName());
        out.close();
        in.close();
    }
}

package org.westos.demo;

import java.io.*;
import java.util.ArrayList;

public class MyTest2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Student student1 = new Student("李白", 22,'男');
        Student student2 = new Student("杜甫", 24,'男');
        Student student3 = new Student("王维", 23,'女');

        //如果我们要序列化多个对象,我们一个个去存这个对象。我们可以把这多个对象,
        // 放到一个容器中,把容器序列化到文件中
        ArrayList<Student> list = new ArrayList<>();
        list.add(student1);
        list.add(student2);
        list.add(student3);

        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("a.txt"));

        out.writeObject(list);
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("a.txt"));
        Object object = in.readObject();
        ArrayList<Student> arrayList= (ArrayList<Student>) object;
        Student student = arrayList.get(0);
        System.out.println(student);
        in.close();
        out.close();

    }
}

2.序列化时候的黄色警告线问题

	- 我们的一个类可以被序列化的前提是需要这个类实现Serializable接口,就需要给这个类添加一个标记.
	- 在完成序列化以后,序列化文件中还存在一个标记,然后在进行反序列化的时候,
	  会验证这个标记和序列化前的标记是否一致,如果一致就正常进行反序列化,如果
	- 不一致就报错了. 而现在我们把这个类做了修改,将相当于更改了标记,而导致这两个标记不一致,就报错了.
	- 
	- 解决问题: 只要让这个两个标记一致,就不会报错了吧 
	- 怎么让这两个标记一致呢? 	不用担心,很简单,难道你们没有看见黄色警告线吗? alt+enter, 生成出来
	private static final long serialVersionUID = -7602640005373026150L;

Java序列化的机制是通过判断类的serialVersionUID来验证版本是否一致的。
在进行反序列化时,JVM会把传来的字节流中的serialVersionUID和本地相应实体类的serialVersionUID进行比较,如果相同说明是一致的,可以反序列化;
否则,会出现InvalidCastException。
package org.westos.demo;

import java.io.*;

public class MyTest3 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //序列化时候的黄色警告线问题
        //writeData();
        //当writeData()方法执行完后,修改Student类,例如去掉age的权限修饰符
        //读取时会报InvalidClassException异常
        readData();


    }

    private static void readData() throws IOException, ClassNotFoundException {
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("b.txt"));
        Object object = in.readObject();
        Student s= (Student) object;
        System.out.println(s);
        in.close();
    }


    private static void writeData() throws IOException {
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("b.txt"));

        Student student = new Student("李白", 22, '男');

        //将student对象序列化保存到对象中
        out.writeObject(student);
        out.close();
    }
}

3.transient关键字

如何让对象的成员变量不被序列化:对象不被存储,例如使用transient关键字存储引用类型
		存储的就是null
		使用transient关键字声明不需要序列化的成员变量
	
		private transient int age ;// 可以阻止成员变量的序列化使用transient
package org.westos.demo;

import java.io.Serializable;

public class Student implements Serializable {
    private String name;
    private transient int age;
    private char sex;

    public Student() {
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                '}';
    }

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

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public Student(String name, int age, char sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
}
------------------------------
package org.westos.demo;

import java.io.*;

public class MyTest4 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        writeData();
        readData();
    }
    private static void readData() throws IOException, ClassNotFoundException {
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("b.txt"));
        Object object = in.readObject();
        Student s= (Student) object;
        System.out.println(s);
        in.close();
    }


    private static void writeData() throws IOException {
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("b.txt"));

        Student student = new Student("李白", 22, '男');

        //将student对象序列化保存到对象中
        out.writeObject(student);
        out.close();
    }
}


七.Properties属性集合

1.概述

A:Properties的概述
		查看API
		Properties 类表示了一个持久的属性集。
		Properties 可保存在流中或从流中加载。
		属性列表中每个键及其对应值都是一个字符串。
		Properties父类是Hashtable
		- 属于双列集合,这个集合中的键和值都是字符串 Properties不能指定泛型
		
		- 属性集合
        Properties 继承自Hashtable 是一个双列集合
        我们经常使用这个集合来读取配置文件。
        Properties 规定了键和值都是String类型

2.Properties的特殊功能使用

	A:Properties的特殊功能
		public Object setProperty(String key,String value)
		public String getProperty(String key)
		public Set<String> stringPropertyNames()
package org.westos.demo;

import java.util.Properties;

public class MyTest {
    public static void main(String[] args) {
        /*属性集合
        Properties 继承自Hashtable 是一个双列集合
        我们经常使用这个集合来读取配置文件。
        Properties 规定了键和值都是String类型*/

        Properties properties = new Properties();
        //使用继承的方法读取
        properties.put("aaa","001");
        properties.put("bbb","002");
        properties.put("ccc","003");

        Object aaa = properties.get("aaa");
        String s= (String) aaa;
        System.out.println(s);
        System.out.println("===================");

        //使用特有的方法进行读取
        Properties properties2 = new Properties();
        properties2.setProperty("aaa","001");
        properties2.setProperty("bbb","002");

        String s2 = properties2.getProperty("aaa");
        System.out.println(s2);

        System.out.println("===========");
        //如果通过键找不到值,返回的是一个null
        String s3 = properties2.getProperty("ccc");
        System.out.println(s3);
        //参数2:是一个默认值,如果通过键没有找到这个对应的值。就返回默认值。
        String ddd = properties2.getProperty("ddd", "默认");
        System.out.println(ddd);

    }
}

3.存储双列集合中的数据到文本文件中

package org.westos.demo;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.function.Consumer;

public class MyTest2 {
    public static void main(String[] args) throws IOException {
        /*把双列集合中的数据,存储到文本文件中保存。
        存储的样子如下
        usename=libai
        password=123456
        email=zpc111@163.com*/
        HashMap<String, String> hm = new HashMap<>();
        hm.put("usename","libai");
        hm.put("password","123456");
        hm.put("email","zpc111@163.com");

        //开启自动刷新
        PrintWriter writer = new PrintWriter(new FileOutputStream("user.properties"),true);

        //获取所有的键
        Set<String> keys = hm.keySet();
        for (String key : keys) {
            String value = hm.get(key);
            System.out.println(key+"==="+value);
        }

        //拿到每一个节点
        Set<Map.Entry<String, String>> entry = hm.entrySet();
        for (Map.Entry<String, String> node : entry) {
            String key = node.getKey();
            String value = node.getValue();
            System.out.println(key+"=="+value);
            writer.println(key+"==="+value);
        }
        System.out.println("==============");

        //通常Properties 集合用来存放配置文件
        Properties properties = new Properties();
        properties.setProperty("aaa","001");
        properties.setProperty("bbb","002");
        properties.setProperty("ccc","003");
        //我们把属性集合中的键值对数据存到配置文件中
        properties.store(new FileWriter("yonghu.properties"),null);
    }
}

4.Properties的load()和store()功能

A:Properties的load()和store()功能
		 Properties和IO流进行配合使用:
		 - public void load(Reader reader):把文件中的键值对加载到集合中
	
	- public void store(Writer writer, String comments)将键值对的属性集合存储到配置文件
package org.westos.demo;

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

public class MyTest4 {
    public static void main(String[] args) throws IOException {
        //public void store(Writer writer, String comments)	存储Properties对象到文本文件
        Properties properties = new Properties();
        properties.setProperty("username","李白");
        properties.setProperty("password","123456");
        properties.setProperty("hobby","足球");

        properties.store(new FileWriter("aaa.properties"),null);
    }
}

5.读取properties配置文件到内存

读取properties配置文件到内存
Properties读取.properties属性配置文件,要求键与值之间用等号拼接。
package org.westos.demo;



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

public class MyTest5 {
    public static void main(String[] args) throws IOException {
        //我有一个配置文件,配置文件是键值对数据  键=值
        //把配置文件中的数据读取到双列集合中
        //要求键与值之间用等号拼接。
        HashMap<String, String> hashMap = new HashMap<>();

        BufferedReader reader = new BufferedReader(new FileReader("user.properties"));
        String s = reader.readLine();
        System.out.println(s);//password===123456
        String[] split = s.split("===");
        //System.out.println(split);打印地址值
        hashMap.put(split[0],split[1]);
        System.out.println(hashMap);
        System.out.println("===================");
        /*使用   Properties 属性集合中的方法,直接就读取到集合里面去了
        Properties 属性集合来取读取配置文件,要求配置文件的中的数据 键和值是以=来拼接的
        一般属性配置文件的后缀名会以 .properties作为扩展名*/

        Properties properties = new Properties();

        //把配置文件中的键值对数据读取到属性集合中
        properties.load(new FileReader("aaa.properties"));
        System.out.println(properties);
        String username = properties.getProperty("username");
        System.out.println(username);

    }
}

package org.westos.demo2;

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

public class MyTest {
    public static void main(String[] args) throws IOException {
        Properties properties = new Properties();
        properties.setProperty("username","李白");
        properties.setProperty("password","123456");
        properties.setProperty("hobby","足球");
        /*
        * - public void load(Reader reader): 从配置文件中读取键值对
	- public void store(Writer writer, String comments)将键值对的属性集合存储到配置文件
        * */
        properties.store(new FileWriter("ccc.properties"),null);

        Properties properties2 = new Properties();
        properties2.load(new FileReader("ccc.properties"));
        String password = properties2.getProperty("password");
        System.out.println(password);

    }
}

安例演示
需求:我有一个文本文件,我知道数据是键值对形式的,但是不知道内容是什么。
请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其值为”100”

package org.westos.demo2;

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

public class MyTest2 {
    public static void main(String[] args) throws IOException {
         /* 例演示
        需求:我有一个文本文件,我知道数据是键值对形式的,但是不知道内容是什么。
        请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其值为”100”*/
        Properties properties = new Properties();
        //把文件中的键值对加载到集合中
        properties.load(new FileReader("ccc.properties"));

        Set<Object> keySet = properties.keySet();

        for (Object key : keySet) {
            if (key.equals("lisi")){
                properties.setProperty((String) key,"100");
            }
        }
        //更改完集合,存储到文件中
        properties.store(new FileWriter("ccc.properties"),null);



    }
}

八.SequenceInputStream

1.概述

SequenceInputStream 
		表示其他输入流的逻辑串联。
		它从输入流的有序集合开始,
		并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,
		依次类推,直到到达包含的最后一个输入流的文件末尾为止
		a:构造方法
		SequenceInputStream(InputStream s1, InputStream s2) 
		通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),
		以提供从此 SequenceInputStream 读取的字节。
		b:构造方法
		SequenceInputStream(Enumeration<? extends InputStream> e) 
		 通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。

2.合并两个文件

package org.westos.demo2;

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

public class MyTest3 {
    public static void main(String[] args) throws IOException {
        /*
        将a.txt和b.txt两个文本文件的内容合并到c.txt
        */
         /*  SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,
        并从第一个输入流开始读取,直到到达文件末尾,
        接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
*/
        FileInputStream in1 = new FileInputStream("a.txt");
        FileInputStream in2 = new FileInputStream("b.txt");
        /*构造方法:
        SequenceInputStream(InputStream s1, InputStream s2)
        通过记住这两个参数来初始化新创建的 SequenceInputStream
        (将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节。
        * */
        SequenceInputStream in = new SequenceInputStream(in1,in2);
        FileOutputStream out = new FileOutputStream("c.txt");
        int len=0;
        byte[] bytes = new byte[1024*8];
        while ((len=in.read(bytes))!=-1){
            out.write(bytes,0,len);
            out.flush();
        }
        in.close();
        out.close();
    }
}

3.合并多个文件

package org.westos.demo2;

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

public class MyTest4 {
    public static void main(String[] args) throws IOException {
        //合并两个配置文件
        FileInputStream in1 = new FileInputStream("a.txt");
        FileInputStream in2 = new FileInputStream("b.txt");
        FileInputStream in3 = new FileInputStream("ccc.properties");
        FileInputStream in4 = new FileInputStream("user.properties");

        SequenceInputStream in = new SequenceInputStream(in1,in2);
        SequenceInputStream in5 = new SequenceInputStream(in, in3);
        SequenceInputStream in6 = new SequenceInputStream(in5, in4);

        FileOutputStream out = new FileOutputStream("all.properties");
        int len=0;
        byte[] bytes = new byte[1024*8];
        while ((len=in6.read(bytes))!=-1){
            out.write(bytes,0,len);
            out.flush();
        }
        in6.close();
        out.close();
    }
}

4.迭代

SequenceInputStream(Enumeration < ? extends InputStream > e)
        通过记住参数来初始化新创建的 SequenceInputStream,
        该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。
package org.westos.demo2;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.Enumeration;
import java.util.Vector;

public class MyTest5 {
    public static void main(String[] args) throws IOException {
        /*SequenceInputStream(Enumeration < ? extends InputStream > e)
        通过记住参数来初始化新创建的 SequenceInputStream,
        该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。*/

        FileInputStream in1 = new FileInputStream("ccc.properties");
        FileInputStream in2 = new FileInputStream("user.properties");
        FileInputStream in3 = new FileInputStream("yonghu.properties");
        //把多个输入流,放到集合vector中
        Vector<FileInputStream> vector = new Vector<>();
        vector.add(in1);
        vector.add(in2);
        vector.add(in3);

        //获取迭代器
        Enumeration<FileInputStream> elements = vector.elements();

        //然后把迭代器传给序列流,他就会去迭代集合中的流
        SequenceInputStream in = new SequenceInputStream(elements);
        FileOutputStream out = new FileOutputStream("out.properties");

        int len=0;
        byte[] bytes = new byte[1024*8];
        while ((len=in.read(bytes))!=-1){
            out.write(bytes,0,len);
        }
        in.close();
        out.close();


    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值