Java--IO流;File类;文件、目录拷贝;序列化与反序列化;Properties

一、IO流

IO流用来处理设备之间的数据传输

数据传输是需要通道的,而IO流就是数据传输的通道;因此IO流可以形象的比喻为运送货物的传输带

I : Input

O : Output

通过IO可以完成硬盘文件的读和写

二、流分类

1、按流向

输入流输出流

以内存作为参照物,

往内存中去,叫做输入(Input),读(Read)
从内存中取出,叫做输出(Output),写(Write)。

2、按数据操作类型

字节流 : 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的

字符流 : 字符流只能操作纯字符数据

字节流,读取二进制,是万能的,什么类型的文件都可以读取,可以处理一切文件,包括:纯文本文件、doc、Word、音频、视频、图片等。

字符流:文本文件,只能处理纯文本;无法读取Word文件

3、按实现功能

节点流(可以从或向一个特定的地方(节点)读写数据。如 FileReader

处理流(是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如

BufferedReader 。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其
他流的多次包装,称为流的链接)

三、流对象

Java中所有的流都是在:java.io.*包下

1、字节流

java.io.InputStream          字节输入流(abstract class,抽象类)
java.io.OutputStream       字节输出流(abstract class,抽象类)

 2、字符流

java.io.Reader                  字符输入流(abstract class,抽象类)
java.io.Writer                    字符输出流(abstract class,抽象类)

所有的流都实现了java.io.Closeable接口,都是可关闭的,都有close()方法
流是一个管道(内存和硬盘之间的通道),用完之后一定要关闭,不然会耗费(占用)很多资源

所有的输出流都实现了java.io.Flushable接口,都是可刷新的,都有flush()方法
刷新表示将通道/管道当中剩余未输出的数据
强行输出完(清空管道!)刷新的作用就是清空管道
如果没有flush()可能会导致丢失数据。

3、java.io包下主要流对象

(1)文件专属:
        java.io.FileInputStream
        java.io.FileOutputStream
        java.io.FileReader
        java.io.FileWriter

(2)转换流:(将字节流转换成字符流)
        java.io.InputStreamReader
        java.io.OutputStreamWriter

(3)缓冲流专属:
        java.io.BufferedReader
        java.io.BufferedWriter
        java.io.BufferedInputStream
        java.io.BufferedOutputStream

(4)数据流专属:
        java.io.DataInputStream
        java.io.DataOutputStream

(5)标准输出流:
        java.io.PrintWriter
        java.io.PrintStream

(6)对象专属流:
        java.io.ObjectInputStream
        java.io.ObjectOutputStream

 

FileInputStream测试代码:tempFile文件中是 abcdef 字符

package iostream;

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

public class FileInputStreamTest {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileInputStream fis1 = null;
        FileInputStream fis2 = null;
        try {
            // 创建文件字节输入流对象
            // 文件路径:D:\file\temp.txt;绝对路径方式 (IDEA会自动把"\"编程为"\\",java中\表示转义)
            //FileInputStream fisTemp = new FileInputStream("D:\\file\\temp.txt");
            // 写成 D:/file/temp.txt 也可以
            FileInputStream fisTemp = new FileInputStream("D:/file/temp.txt");

            /**
             * IDEA默认的当前路径是工程Project的根
             * */
            fis = new FileInputStream("tempFile");

            // 读,采用byte数组,一次读取多个字节。最多读取“数组.length”个字节
            byte[] bytes = new byte[4];

            /**
            int read(byte[] b)
            一次最多读取 b.length 个字节。
            减少硬盘和内存的交互,提高程序的执行效率。
             */
            // 这个方法的返回值是:读取到的字节数量。(不是字节本身);大小一般取值为1024的整数倍
            int readCount = fis.read(bytes);
            System.out.println(readCount); // 第一次读到了4个字节。

            // 将字节数组全部转换成字符串
            //System.out.println(new String(bytes)); // abcd
            // 读取了多少个字节,转换多少
            System.out.println(new String(bytes));

            readCount = fis.read(bytes); // 第二次只能读取到2个字节。
            System.out.println(readCount); // 2
            // 将字节数组全部转换成字符串
            //System.out.println(new String(bytes)); // efcd,ef替换了ab,cd还存在
            System.out.println(new String(bytes));

            readCount = fis.read(bytes); // 1个字节都没有读取到返回-1
            System.out.println(readCount); // -1


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

            fis1 = new FileInputStream("src/iostream/tempFile1");
            byte[] bytes1 = new byte[5]; // 一个5个长度的byte数组,一次最多读取5个字节
            /**
             * int readCount = fis.read(bytes);
             * 返回值是:读取到的字节数量。(不是字节本身)
             * 将字节数组全部转换成字符串,读取了多少字节,转换多少
             *
             * 转换为字符时,使用String(byte [ ]   bytes,int offset,int length)
             */
            int readCount1 = 0;
            while ( (readCount1 = fis1.read(bytes1)) != -1){
                System.out.print(new String(bytes1,0,readCount1));
            }

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

            fis2 = new FileInputStream("src/iostream/tempFile1");
            /**
             * int available():返回流当中剩余的没有读到的字节数量
             * */
            System.out.println("总字节数量:" + fis2.available());
            // 可以读取剩下的字节数;这种方式不太适合太大的文件,因为byte[]数组不能太大。
            byte[] restBytes = new byte[fis.available()];

            //long skip(long n):跳过几个字节不读。
            fis2.skip(5);//

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {// 在finally语句块当中确保流一定关闭。
            // 关闭流的前提是:流不是空;流是null的时候没必要关闭
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis1 != null) {
                try {
                    fis1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis2 != null) {
                try {
                    fis2.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

FileOutputStream

public class FileOutStreanTest {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            // 以追加的方式在文件末尾写入,不会清空原文件内容。
            fos = new FileOutputStream("src/iostream/outFile1",true);

            byte[] bytes = {97,98,99,100};
            fos.write(bytes);

            String str = "这是强大的祖国,是我生长的地方!";
            byte[] bytes1 = str.getBytes();
            fos.write(bytes1);

            //刷新管道
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

BufferedWriter

/**
BufferedWriter:带有缓冲的字符输出流。
OutputStreamWriter:转换流
 */
public class BufferedWriterTest {
    public static void main(String[] args) {
        BufferedWriter bw = null;

        try {
            FileOutputStream fos = new FileOutputStream("src/iostream/outFile2");

            OutputStreamWriter osw = new OutputStreamWriter(fos);

//            bw = new BufferedWriter(osw);
            bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("src/iostream/outFile2")));

            bw.write("Hello World!");
            bw.write("\n");
            bw.write("Hello");

            bw.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bw != null) {
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

 BufferedReader

/**
BufferedReader:
    带有缓冲区的字符输入流。
    使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组。自带缓冲。
转换流:InputStreamReader
 */
public class BufferedReaderTest {
    public static void main(String[] args) {
        BufferedReader br = null;
        BufferedReader br1 = null;
        try {
            /**
             当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流。
             外部负责包装的这个流,叫做:包装流,还有一个名字叫做:处理流。
             像当前这个程序来说:FileReader就是一个节点流。BufferedReader就是包装流/处理流。
            */
            FileReader fr = new FileReader("src/iostream/tempFile1");
            br = new BufferedReader(fr);

            String str = null;
            while ((str = br.readLine()) != null){
                System.out.println(str);
            }
            
            
            //字节流
            FileInputStream fis = new FileInputStream("src/iostream/tempFile1");

            /**
             * 转换流
             * 通过转换流转换(InputStreamReader将字节流转换成字符流)
             * in是节点流。reader是包装流
             */
            InputStreamReader isr = new InputStreamReader(fis);


            /**
             * 这个构造方法只能传一个字符流。不能传字节流。
             * reader是节点流。br是包装流。
             * */
            //new BufferedReader(isr);
            br1 = new BufferedReader(new InputStreamReader(new FileInputStream("src/iostream/tempFile1")));

            String str = null;
            while ((str = br1.readLine()) != null){
                System.out.println(str);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    // 对于包装流来说,只需要关闭最外层流就行,里面的节点流会自动关闭(源码)
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (br1 != null) {
                try {
                    br1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

DataOutputStream

/**
 java.io.DataOutputStream:数据专属的流。
 这个流可以将数据连同数据的类型一并写入文件。
 注意:这个文件不是普通文本文档。(这个文件使用记事本打不开。)
 */
public class DataOutputStreamTest {
    public static void main(String[] args) {
        DataOutputStream dos = null;
        try {
            // 创建数据专属的字节输出流
            dos = new DataOutputStream(new FileOutputStream("src/iostream/dataInput"));

            // 写数据
            byte b = 100;
            short s = 200;
            int i = 300;
            long l = 400L;
            float f = 3.0F;
            double d = 3.14;
            boolean sex = false;
            char c = 'a';

            // 把数据以及数据的类型一并写入到文件当中。
            dos.writeByte(b);
            dos.writeShort(s);
            dos.writeInt(i);
            dos.writeLong(l);
            dos.writeFloat(f);
            dos.writeDouble(d);
            dos.writeBoolean(sex);
            dos.writeChar(c);

            dos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dos != null) {
                try {
                    dos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

DataInputStream

/**
DataInputStream:数据字节输入流。
DataOutputStream写的文件,只能使用DataInputStream去读。并且读的时候你需要提前知道写入的顺序。
读的顺序需要和写的顺序一致。才可以正常取出数据。
 */
public class DataInputStreamTest {
    public static void main(String[] args) {
        DataInputStream dis = null;
        try {
            dis = new DataInputStream(new FileInputStream("src/iostream/dataInput"));

            byte b = dis.readByte();
            short s = dis.readShort();
            int i = dis.readInt();
            long l = dis.readLong();
            float f = dis.readFloat();
            double d = dis.readDouble();
            boolean sex = dis.readBoolean();
            char c = dis.readChar();

            System.out.println(b);
            System.out.println(s);
            System.out.println(i);
            System.out.println(l);
            System.out.println(f);
            System.out.println(d);
            System.out.println(sex);
            System.out.println(c);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dis != null) {
                try {
                    dis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

PrintStream

/**
 * 日志工具
 * */
public class Logger {
    public static void log(String message){
        try {
            // 标准输出流不需要手动close()关闭
            PrintStream printStream = new PrintStream(new FileOutputStream("src/iostream/log.txt",true));

            // 修改输出方向,将输出方向修改到"log.txt"文件;标准输出流不再指向控制台,指向"log.txt"文件。
            System.setOut(printStream);

            Date date = new Date();
            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
            String timeStr = sf.format(date);
            printStream.println(timeStr + ": " + message);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

四、File

1、File类父类是Object,因此File不能完成文件的读和写

2、File对象    

文件和目录路径名的抽象表示形式;File只是一个路径名的抽象表示形式

C:\Download 这是一个File对象;C:\Drivers\Download\a.txt 也是File对象    

一个File对象有可能对应的是目录,也可能是文件    

public class FileTest {
    public static void main(String[] args) {
        //创建一个File文件
        File file = new File("D:\\file");

        // exists()判断文件是否存在
        System.out.println(file.exists());

        //如果不存在,以文件形式创建文件createNewFile()
        if (!file.exists()){
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //isDirectory()判断是否文件夹
        System.out.println(file.isDirectory());

        //isFile()判断是否文件
        System.out.println(file.isFile());

        //getName()获取文件名
        System.out.println(file.getName());

        //length()获取文件大小(返回字节大小)
        System.out.println(file.length());

        //lastModified()判断最后一次修改时间
        long millisecond = file.lastModified();
        Date date = new Date(millisecond);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        System.out.println(sdf.format(date));


        //mkdir()如果不存在,以文件夹目录形式创建文件
        if (!file.exists()){
//            file.mkdir();
        }

        //mkdirs()以多重文件夹目录形式创建文件
        File file2 = new File("D:\\file1\\file11\\file111");
//        file2.mkdirs();

        File file3 = new File("D:\\文件\\24节气.jpg");
        //getParent()获取父类文件的路径
        String parentPath = file3.getParent();
        System.out.println(parentPath);

        //getParentFile()获取父类文件
        File parentFile = file3.getParentFile();
        System.out.println(parentFile);

        //getAbsolutePath()获取绝对路径
        System.out.println("文件绝对路径:" + file3.getAbsolutePath());

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

        //listFiles() 获取当前目录下所有的子文件
        File file4 = new File("D:\\文件");
        File[] files = file4.listFiles();

        for (File oneFile:files) {
            System.out.println(oneFile.getName());
        }
    }
}

五、文件、目录拷贝

拷贝原理

 1、拷贝文件

public class FileCopy {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;

        try {
            fis = new FileInputStream("D:/file/养生.pdf");
            fos = new FileOutputStream("D:/file/养生.pdf");

            byte[] bytes = new byte[1024 * 1024];//读取1MB
            int readCount = 0;
            //边读边写
            while ((readCount = fis.read(bytes)) != -1) {
                fos.write(bytes,0,readCount);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

2、拷贝文件目录(文件夹和文件

/**
 * 将一个文件目录拷贝到另一个盘下
 * */
public class FileAllCopy {
    public static void main(String[] args) {
        File srcFile = new File("D:\\temp");
        File destFile = new File("D:\\TempFile\\");

        copyFiles(srcFile,destFile);
    }

    /**
     * 复制文件目录
     *
     * @param srcFile       源文件
     * @param destFile      目标文件
     */
    private static void copyFiles(File srcFile, File destFile) {
        //如果是文件,则终止递归;且将文件拷贝到目标路径下
        if (srcFile.isFile()){
            System.out.println("文件:" + srcFile.getAbsolutePath());

            FileInputStream fis = null;
            FileOutputStream fos = null;

            try {
                fis = new FileInputStream(srcFile);

                //一次读取1MB
                byte[] bytes = new byte[1024 * 1024];

                //获取源文件目录路径
                String srcPath = srcFile.getAbsolutePath().substring(3);
                //目标文件目录路径
                String tempPath = destFile.getAbsolutePath().endsWith("\\") ? destFile.getAbsolutePath() : destFile.getAbsolutePath() + "\\";
                String destPath = tempPath + srcPath;

                fos = new FileOutputStream(destPath);

                int readCount = 0;
                while ((readCount = fis.read(bytes)) != -1){
                    fos.write(bytes,0,readCount);
                }

                //刷新
                fos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

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

            return;
        }

        //获取源目录的所有子文件
        File[] files = srcFile.listFiles();
        //遍历所有子文件
        for (File src:files) {
            //如果是文件夹,判断是否存在;存在继续递归新建;不存在创建文件夹且继续递归
            if (src.isDirectory()){
//                System.out.println("文件夹:" + file.getAbsolutePath());

                //获取源文件目录路径
                String srcPath = src.getAbsolutePath().substring(3);
                //目标文件目录路径
                String tempPath = destFile.getAbsolutePath().endsWith("\\") ? destFile.getAbsolutePath() : destFile.getAbsolutePath() + "\\";
                String destPath = tempPath + srcPath;

//                System.out.println("源文件目录路径:" + srcPath);
                System.out.println("目标文件目录路径:" + destPath);

                //不存在创建多重目录
                File dest = new File(destPath);
                if (!dest.exists()){
                    dest.mkdirs();
                }
            }

            //递归创建文件目录
            copyFiles(src,destFile);
        }
    }
}

六、序列化与反序列化

1、java序列化

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流

化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象

流进行读写操作时所引发的问题

 2、实现 java 序列化

序列化的实现,将需要被序列化的类实现Serializable 接口,该接口没有需要实现的方法,

implements Serializable 只是为了标注该对象是可被序列化的,然后使用一个输出流(如:

FileOutputStream)来构造一个 ObjectOutputStream(对象流)对象,接着,使用

ObjectOutputStream 对象的 write Object(Object obj)方法就可以将参数为 obj 的对象写出(即保

存其状态),要恢复的话则用输入流

3、参与序列化和反序列化的对象,必须实现 Serializable 接口,不然抛出异常    异常:    java.io.NotSerializableException: iostream.bean.Student    Student对象不支持序列化

4、序列化多个对象(集合)  

(1)将对象放到集合当中,序列化集合。   参与序列化的ArrayList集合以及集合中的元素都需要实现 java.io.Serializable接口  

(2)ArrayList 也实现了 java.io.Serializable 接口        public class ArrayList<E> extends AbstractList<E>          implements List<E>, RandomAccess, Cloneable, java.io.Serializable

5、参与序列化和反序列化的对象,必须实现Serializable接口

6、源码中,Serializable接口当中什么代码都没有,只是一个标志接口:  

 public interface Serializable {    }  

标志接口起到标识标志的作用,java虚拟机看到这个类实现了这个接口,可能会对这个类进行特殊操作   java虚拟机看到Serializable这个标志接口之后,会为该类自动生成一个序列化版本号

7、序列化版本号  

(1)如果直接修改了Student类,再去反序列化,这时会抛出异常  

 java.io.InvalidClassException: iostream.bean.Student;    local class incompatible:    

stream classdesc serialVersionUID = 4869515950171901002,  

local class serialVersionUID = 5648694406856253046  

(2)Java中区分类的机制    

        【1】首先通过类名进行比对,如果类名不一样,肯定不是同一个类    

        【2】如果类名一样,再通过序列化版本号进行区分  

(3)自动生成序列化版本号    

Java虚拟机看到Serializable接口之后,会自动生成一个序列化版本号    

private static final long serialVersionUID = 5648694406856253046L;    

即使没有手动写出来,java虚拟机会默认提供这个序列化版本号。    

如果不同的程序员编写了同一个类,但“这两个类确实不是同一个类”    

对于java虚拟机来说,这两个类都实现了Serializable接口;都有默认的序列化版本号,他们的序列化版本号不一样  

(4)自动生成序列化版本号优缺点    

优点:自动生成可以去分类    

缺点:自定义对象创建之后不能再做修改,只要修改会重新编译,会导致生成全新的序列化版本号,这时java虚拟机会认为是一个新的类

8、一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号     即使这个类代码被修改,只要序列化版本号不变,java虚拟机会认为是同一个类

Student类

/**
 1、参与序列化和反序列化的对象,必须实现 Serializable 接口,
 不然抛出异常
 java.io.NotSerializableException: iostream.bean.Student
 Student对象不支持序列化
 * */
public class Student implements Serializable {
    /**
     * Java虚拟机看到Serializable接口之后,会自动生成一个序列化版本号
     * 没有手动写出来,java虚拟机会默认提供这个序列化版本号
     * IDEA也会自动生成序列化版本号
     * */
    //private static final long serialVersionUID = 5648694406856253046L;

    /**
     * 之后,Student类源代码被别的程序员改动,会重新编译,生成新的字节码文件,且class文件再次运行,java虚拟机也会自动生成新的序列化版本号
     * java虚拟机识别一个类的时候先通过类名,如果类名一致,再通过序列化版本号
     * 建议将序列化版本号手动的写出来不建议自动生成
     * */
    private static final long serialVersionUID = 1L;

    private int age;
    private String name;

    /**
     * 序列化之后被别的程序员修改,此时再反序列化会抛异常
     * java.io.InvalidClassException: iostream.bean.Student;
     * local class incompatible:
     * stream classdesc serialVersionUID = 4869515950171901002,
     * local class serialVersionUID = 5648694406856253046
     *
     * 加上固定的private static final long serialVersionUID = 1L; 就不会抛异常了
     * */
//    private String address;

    public Student(){

    }

    public Student(int age,String name){
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString(){
        return "Student[age = " + this.age + ",name = " + this.name + "]";
    }
}

ObjectOutputStream

public class ObjectOutputStreamTest {
    public static void main(String[] args) {
        ObjectOutputStream oos = null;
        ObjectOutputStream oos1 = null;
        try {
            System.out.println("========序列化单个对象========");
            oos = new ObjectOutputStream(new FileOutputStream("src/iostream/student"));

            // Java
            Student s = new Student(18,"张小五");

            // 序列化Java对象
            oos.writeObject(s);

            //刷新流
            oos.flush();


            System.out.println("========序列化数组对象========");

            oos1 = new ObjectOutputStream(new FileOutputStream("src/iostream/students"));

            /**
             * 1、一次序列化多个对象
             *  将对象放到集合当中,序列化集合。
             *  参与序列化的ArrayList集合以及集合中的元素都需要实现 java.io.Serializable接口
             * 2、ArrayList 也实现了 java.io.Serializable 接口
             * public class ArrayList<E> extends AbstractList<E>
             *         implements List<E>, RandomAccess, Cloneable, java.io.Serializable
             * */
            //创建List数组
            List<Student> list = new ArrayList<>();
            Student s1 = new Student(17,"王五");
            Student s2 = new Student(16,"李四");
            Student s3 = new Student(19,"王二");
            Student s4 = new Student(15,"铁蛋");
            Student s5 = new Student(16,"二狗");
            list.add(s1);
            list.add(s2);
            list.add(s3);
            list.add(s4);
            list.add(s5);
            oos1.writeObject(list);

            oos1.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (oos1 != null) {
                try {
                    oos1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

ObjectInputStream

public class ObjectInputStreamTest {
    public static void main(String[] args) {
        ObjectInputStream ois = null;
        ObjectInputStream ois1 = null;
        try {
            System.out.println("========反序列化单个对象========");
            ois = new ObjectInputStream(new FileInputStream("src/iostream/student"));
            // 开始反序列化,读
            Student s = (Student) ois.readObject();
            System.out.println(s);//Student[age = 18,name = 张小五]


            System.out.println("========序列化数组对象========");
            ois1 = new ObjectInputStream(new FileInputStream("src/iostream/students"));
            // 开始反序列化,读
            List<Student> list = (List<Student>) ois1.readObject();
            for (Student student:list) {
                System.out.println(student);
            }
            /*
            Student[age = 17,name = 王五]
            Student[age = 16,name = 李四]
            Student[age = 19,name = 王二]
            Student[age = 15,name = 铁蛋]
            Student[age = 16,name = 二狗]
            */

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (ois1 != null) {
                try {
                    ois1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

七、IO + Properties集合

IO+Properties的联合使用

1、设计理念:    

经常改变的数据,可以单独写到一个文件中,使用程序动态读取。    

以后只需要修改这个文件的内容,java代码不需要改动,不需要重新编译,服务器也不需要重启。就可以拿到动态的信息    

以上机制的这种文件被称为配置文件    

并且当配置文件中的内容格式是:        

        key=value    

把这种配置文件叫做属性配置文件

2、Java规范中要求:

属性配置文件建议以 .properties 结尾,但不是必须的  

这种以.Java规范中要求:属性配置文件  

Properties是专门存放属性配置文件内容的类

userInfo.properties

#建议key和value之间使用=方式
#=左边是key,=右边是value
username=admin
password=123456
#尽量不要有空格
name  =  zhangsan
#尽量不使用冒号:
#usernamex:admin
#属性配置文件的key重复的话,value会自动覆盖!
#password=admin123
public class IOPropertiesTest {
    public static void main(String[] args) {
        FileReader fr = null;
        try {
            //输入流对象
            fr = new FileReader("src/iostream/userInfo.properties");

            /**
             Properties是一个Map集合,key和value都是String类型
             将userinfo文件中的数据加载到Properties对象当中
             */
            Properties ps = new Properties();

            /**
             * 调用Properties对象的load()方法将文件中的数据加载到Map集合中
             * 文件中的数据顺着流管道加载到Map集合中,其中 等号= 左边是key,等号= 右边是value
             * */
            ps.load(fr);

            String userName = ps.getProperty("username");
            String passWord = ps.getProperty("password");
            System.out.println(userName);
            System.out.println(passWord);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

八、BIO、NIO、AIO

1、BIO
BIO 就是传统的 java.io 包,它是基于流模型实现的,交互的方式是同步、阻塞方式,也就是
说在读入输入流或者输出流时,在读写动作完成之前,线程会一直阻塞在那里,它们之间的调
用时可靠的线性顺序。它的有点就是代码比较简单、直观;缺点就是 IO 的效率和扩展性很
低,容易成为应用性能瓶颈。
2、NIO
Java 1.4 引入的 java.nio 包,提供了 Channel Selector Buffer 等新的抽象,可以构建
多路复用的、同步非阻塞 IO 程序,同时提供了更接近操作系统底层高性能的数据操作方式。
3、AIO
AIO Java 1.7 之后引入的包,是 NIO 的升级版本,提供了异步非堵塞的 IO 操作方式,所以
人们叫它 AIO Asynchronous IO ),异步 IO 是基于事件和回调机制实现的,也就是应用操
作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续
的操作
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值