IO学习笔记

IO

一、IO概述

1.什么是IO

​ 输入和输出都是相对内存来说的,从硬盘往内存中存就是输入,从内存往硬盘中存就是输出。以下图也可也解释:
在这里插入图片描述

2.分类方式

​ 有多种分类方式,一种是按照流的方向进行分类:

​ 以内存作为参考,往内存中去,叫做输入(input),或者叫做读。从内存中出去,叫做输出(output),或者叫做写。

​ 另一种按照读取数据方式不同进行分类:

​ 字节流:一次读取一个字节byte,等同于一次读取8个二进制,这种流是万能的,什么都可以读。

​ 字符流:一次读取一个字符,这种流是为了方便读取普通文本文件而存在的。

3.四大家族

​ java.io.InputStream 字节输入流

​ java.io.OutputStream 字节输出流

​ java.io.Reader 字符输入流

​ java.io.Writer 字符输出流

​ 四大家族的首领都是抽象类(Abstract),所有的流都实现了Closeable接口,都是可关闭的,都有close()方法。流是一个管道,是内存和硬盘中的通道,用完之后要关闭。

所有的输出流都实现了Flushable接口,都是可刷新的,都有flush()方法,输出流在最终输出之后,要刷新flush一下,这个刷新表示将通道/管道当中剩余未输出的数据强行输出完。如果没有flush(),可能会丢失数据。

​ 注意:以"Stream"结尾的都是字节流,以"Reader/Writer"结尾的都是字符流。

4.需要掌握的流

​ 在java.io下需要掌握的流有16个:

文件专属:

  • java.io.FileInputStream
  • java.io.FileOutputStream
  • java.io.FileReader
  • java.io.FileWriter

转换流(将字节流转换成字符流的)

  • java.io.InputStreamReader
  • java.io.OutputStreamWriter

缓冲流专属:

  • java.io.BufferedInputStream
  • java.io.BufferedOutputStream
  • java.io.BufferedReader
  • java.io.BufferedWriter

数据流专属:

  • java.io.DataInputStream
  • java.io.DataOutputStream

对象专属流:

  • java.io.ObjectInputStream
  • java.io.ObjectOutputStream

标准输出流:

  • java.io.PrintWriter
  • java.io.PrintStream

二、文件专属流

​ 文件专属流有FileInputStream、FileOutputStream、FileReader、FileWriter四种,以下重点讲解FileInputStream和FileOutputStram。

1.FileInputStream

​ FileInputStream是文件字节输入流,完成读的操作(从硬盘到内存),是万能的,任何类型的文件都可以采用这个流来读。

​ 现在有一个文件:test.txt,路径为:C:\Users\DRL\Desktop\test,IDEA中会把"“变成”\",因为java中反斜杠表示转义,以下是使用read的不同方式来读。

1.1 read()

read()方法返回字节的ASCALL码大小,指针指向最后一个字节之后会返回-1,示例图如下:
在这里插入图片描述

代码及结果如下:

public static void main(String[] args) {

    FileInputStream fis=null;
    try {
        //创建流
        fis=new FileInputStream("C:\\Users\\DRL\\Desktop\\test.txt");
        //开始读
       int readData=0;
       while ((readData=fis.read())!=-1){
           System.out.println(readData);
       }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fis!=null){
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述

1.2 read(byte[] b)

​ 使用read()方法一次只能读一个字节,过于慢,可以使用read(byte[ ] b),返回数组中的元素个数,一次最多可以读b.length个字节,往byte数组中读。

​ 当文件中的字节未被读完时,可以再次进行read(byte[] b)方法读取,当文件中的字节全部读完会返回-1。

​ 【注意】:若文件中有7个字节,分别是abcdef,byte数组容量为4,第一次取4个字节为abcd,剩下了两个字节ef,那么第二次取字节会将第一次的前两个覆盖掉,取出的字节为efcd,第三次由于文件中没有可以取出的字节,那么就会返回-1,如下图所示:
在这里插入图片描述

​ 代码及结果如下:

public static void main(String[] args) {
    FileInputStream fis=null;
    try {
        fis=new FileInputStream("C:/Users/DRL/Desktop/test.txt");
        byte[] bytes=new byte[4];
        int readCount=0;
        while ((readCount=fis.read(bytes))!=-1){
            System.out.print(new String(bytes,0,readCount));
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

}

在这里插入图片描述

1.3 available

​ 方法全称为:int available( ),返回当前流中剩余的没有读到的字节数量,使用方法如下:

public static void main(String[] args) {
    FileInputStream fis=null;
    try {
        //一共有6个字节
        fis=new FileInputStream("C:\\Users\\DRL\\Desktop\\test.txt");
        int read=fis.read();//读了一个字节
        System.out.println(fis.available());//还剩下5个字节没有读
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fis == null) {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

​ 这个方法也可以和read(byte[ ] b)配合使用,可以先获取文件中的字节数,然后将其传参给byte数组,直接遍历文件中的字节,使用方法如下:

public static void main(String[] args) {
    FileInputStream fis=null;
    try {
        fis=new FileInputStream("C:\\Users\\DRL\\Desktop\\test.txt");
        byte[] bytes=new byte[fis.available()];//使用available方法创建文件中字节大小的数组
        int readCount=0;
        while ((readCount=fis.read(bytes))!=-1){
            System.out.println(new String(bytes));
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fis == null) {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
1.4 skip

​ 方法的全称是:long skip(long n),将会跳过n个字节,使用方法如下:

public static void main(String[] args) {
    FileInputStream fis=null;
    try {
        fis=new FileInputStream("C:\\Users\\DRL\\Desktop\\test.txt");
        byte[] bytes=new byte[fis.available()];//使用available方法创建文件中字节大小的数组
        int readCount=0;
        fis.skip(3);
        //while循环之后是def,跳过了3个字节,将abc跳过了
        while ((readCount=fis.read(bytes))!=-1){
            System.out.println(new String(bytes));
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fis == null) {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
2.FileOutputStream

​ 文件字节输出流,负责写,从内存到硬盘。

​ FileOutputStream的构造方法有两种,一种是只带有文件名的构造方法,这种很有可能会将原先文件中的数据清空,然后重写入新数据。另一种是带有两个参数,分别是文件名和boolean类型的参数append,若为true,则将数据写入原文件末尾,若为false,则将数据写入文件中的原数据全部删除,然后写上新数据。代码和文档截图如下:
在这里插入图片描述

public static void main(String[] args) {
    FileOutputStream fos=null;
    try {
        //创建流,并将数据写入"myFile"文件的末尾处
        fos=new FileOutputStream("myFile",true);
        //创建流,并将文件"myFile"中的数据清除之后添加新的数据
//            fos=new FileOutputStream("myFile",false);
        //先给byte数组中添加数据
        byte[] bytes={102,103,104,105};
        fos.write(bytes);
        //写完之后要刷新
        fos.flush();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fos != null) {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
2.1 写入字符串

​ 要向文件中写入字符串类型数据时,需要先将字符串转换成buye数组,然后向文件中写入byte数组,代码如下:

public static void main(String[] args) {
    FileOutputStream fos=null;
    try {
        fos=new FileOutputStream("myFile",false);
        String a="我爱中国!";
        //将字符串转换为byte数组
        byte[] bytes=a.getBytes();
        //写入文件
        fos.write(bytes);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fos != null) {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
2.2 拷贝文件

​ 【注意】:FileInputStream和FileOutputStream对任何文件都可以进行读写!

​ 利用FileInputStream和FileOutputStream进行文件的拷贝,比如有一个文件需要从D盘拷到C盘,拷贝过程中,将文件从D盘中读到内存中,同时将文件从内存写入到D盘中,以下是拷贝的简单实现:

public static void main(String[] args) {
    BufferedReader br=null;
    String s;
    try {
//            //创建文件输入字节流
//            FileInputStream in=new FileInputStream("myFile");
//            //由于字节流无法直接作为参数传入BufferedReader中,需要转换流将其转换成字符流
//            InputStreamReader reader=new InputStreamReader(in);
//            //将转换好的fis参入BufferedReader中
//            br=new BufferedReader(reader);
        //合并之后如下一行即可解决
        br=new BufferedReader(new InputStreamReader(new FileInputStream("myFile")));
        while ((s=br.readLine())!=null){
            System.out.println(s);
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(br!=null){
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
3.FileReader

​ 【注意】:word文件不是普通文本,故不能用FileReader来读。

​ FileReader是文件字符输入流,需要用char数组来存,只能读取普通文本,在读取文本时比较方便快捷,FileReader的使用方式和FileInputStream类似,以下是其使用方法:

public static void main(String[] args) {
    FileReader reader=null;
    try {
        //构造输入流
        reader=new FileReader("myFile");
        //创建字符数组来存储从内存读到的字符
        char[] chars=new char[10];
        int readCount=0;
        //开始读
        while ((readCount=reader.read(chars))!=-1){
            System.out.print(new String(chars,0,readCount));
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
4.FileWriter

​ 【注意】:word不是普通文本,故不能用FileWriter来写。

​ FileWriter是文件字符输出流,只能输出普通文本,其和FileOutputStream使用方式类似。

​ Writer的构造方法有两种,一种是只带有文件名的构造方法,这种很有可能会将原先文件中的数据清空,然后重写入新数据。另一种是带有两个参数,分别是文件名和boolean类型的参数append,若为true,则将数据写入原文件末尾,若为false,则将数据写入文件中的原数据全部删除,然后写上新数据。代码和文档截图如下:
在这里插入图片描述

public static void main(String[] args) {
    FileWriter writer=null;
    try {
        //构造文件输出流对象
        writer=new FileWriter("copyFile");
        //char数组中存入要输出给文件的数据
        char[] chars={'你','好','吗','?'};
        writer.write(chars);
        //刷新
        writer.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        if (writer != null) {
            try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

​ FileWriter也可以直接写入字符串,以下为示例代码:

public static void main(String[] args) {
    FileWriter writer=null;
    try {
        //构造文件输出流对象
        writer=new FileWriter("copyFile");
        //char数组中存入要输出给文件的数据
        String s="你现在过的怎么样?";
        writer.write(s);
        //刷新
        writer.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        if (writer != null) {
            try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
4.1 拷贝文件

​ 利用FileReader和FileWriter来拷贝文本文件。

​ 【注意】:只能拷贝文本文件,word文件也不可以!代码如下:

public static void main(String[] args) {
    FileReader reader=null;
    FileWriter writer=null;
    try {
        //构造文件输入流对象
        reader=new FileReader("myFile");
        //构造文件输出流对象
        writer=new FileWriter("copyFile");
        int readCount=0;
        //char数组,用来暂时存放要拷贝的数据
        char[] chars=new char[5];
        while ((readCount=reader.read(chars))!=-1){
            writer.write(new String(chars,0,readCount));
        }
        //刷新
        writer.flush();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    finally {
        if (reader!=null){
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (writer!=null){
            try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

三、缓冲流

1.BufferedReader

​ 带有缓冲区的字符输入流,使用这个流的时候不需要自定义char/byte数组,自带缓冲。

​ 构造BufferedReader对象时,需要传入另外一个字符流作为参数,并且这个流叫做节点流,外部负责包装的流叫做包装流或处理流。若想要传入字节流,那么需要将字节流转换成字符流,用InputStreamReader/OutputStreamWriter来转换,使用方法如下:

public static void main(String[] args) {
    BufferedReader br=null;
    String s;
    try {
        //创建文件输入字节流
        FileInputStream in=new FileInputStream("myFile");
        //由于字节流无法直接作为参数传入BufferedReader中,需要转换流将其转换成字符流
        InputStreamReader reader=new InputStreamReader(in);
        //将转换好的fis参入BufferedReader中
        br=new BufferedReader(reader);
        while ((s=br.readLine())!=null){
            System.out.println(s);
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(br!=null){
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

对于下面这个程序代码来说,BufferedReader就是包装流/处理流,FileReader就是节点流。要关闭流时,只需要关闭包装流/处理流,节点流在底层已经被关闭了。

//构建BufferedReader之前需要构建一个字节流进行参数传入
        FileReader fileReader=new FileReader("myFile");
        //构建BufferedReader,并传入fileReader参数
        reader=new BufferedReader(fileReader);
1.1 readLine方法

​ 方法全称为:String readLine(),返回值为String类型,可以一行一行读文本,但不带换行符,在读完一行之后需要手动换行,当文本中数据读完时会返回null,使用方法如下:

public static void main(String[] args) {
    BufferedReader bufferedReader=null;
    String s=null;
    try {
        bufferedReader=new BufferedReader(new FileReader("myFile"));
        while ((s=bufferedReader.readLine())!=null){
            System.out.println(s);
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        if (bufferedReader!=null){
            try {
                bufferedReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
2.BufferedWriter

​ BufferedWriter是缓冲输出流,和BufferedReader用法一样,要传字符输出流参数,若想传字节输出流参数的话,需要用OutputStreamWriter来将字节流转换成字符流,使用方法如下:

public static void main(String[] args) {
    //创建BufferedWriter对象
    BufferedWriter bw=null;
    try {
        //构建BufferedWriter对象
//            bw=new BufferedWriter(new FileWriter("copyFile"));
        //若要将字节输出流作为参数传进去,则需要OutputStreamWriter进行转换
        bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("copyFile")));
        bw.write("你好呀!");
        bw.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        if (bw!=null){
            try {
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
2.1拷贝文件

​ 利用缓冲流拷贝文件,以下是节点流为字符流的例子,如果节点流为字节流,那么需要将子节点转换为字符流再进行传参:

public static void main(String[] args) {
    BufferedReader br=null;
    BufferedWriter bw=null;
    String s=null;
    try {
        //利用字符流输入输出进行拷贝文件
        br=new BufferedReader(new FileReader("myFile"));
        bw=new BufferedWriter(new FileWriter("copyFile"));
        //利用字节流作为节点流,则需要将字节流转换为字符流
        br=new BufferedReader(new InputStreamReader(new FileInputStream("myFile")));
        bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("copyFile")));
        while((s=br.readLine())!=null){
            bw.write(s);
            bw.write("\n");
        }
        //输出流用完要刷新
        bw.flush();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (br!=null){
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (bw!=null){
            try {
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

四、数据流(了解)

​ 数据专属的流,这个流可以将数据连通数据的类型一并写入文件。

​ 【注意】:这个文件不是普通文档(用记事本打不开)。

1.DataOutputStream

​ 数据输出字节流,需要传入节点流,并且节点流也为字节流,使用DataOutputStream流输出,不仅会将数据输出,也会将数据的类型输出,用记事本打开会乱码,这种文件只能用DataInputStream输入,所以这个流用的不多,以下是其使用方法:

public static void main(String[] args) {
    DataOutputStream dos=null;
    try {
        //构造数据输出字节流,需要传入节点流
        dos=new DataOutputStream(new FileOutputStream("myFile",false));
        byte b=10;
        short s=20;
        int i=100;
        long l=500L;
        char c='a';
        //将以上数据输出文件中,不仅会将数据本身输出,也会将数据类型一并输出
        dos.writeByte(b);
        dos.writeShort(s);
        dos.writeInt(i);
        dos.writeLong(l);
        dos.writeChar(c);
        //刷新
        dos.flush();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }finally{
        if(dos!=null){
            dos.close();
        }
    }
}

输出结果用记事本打开之后乱码,如下:
在这里插入图片描述

2.DataInoutStream

​ 数据输入字节流,用数据输出字节流输出的文件只能用这个流来读,代码如下:

public static void main(String[] args) {
    DataInputStream dis=null;
    try {
        //构造数据输入字节流对象,并传入节点流
        dis=new DataInputStream(new FileInputStream("myFile"));
        byte b=dis.readByte();
        short s=dis.readShort();
        int i=dis.readInt();
        long l=dis.readLong();
        char c=dis.readChar();
        System.out.println(b);
        System.out.println(s);
        System.out.println(i);
        System.out.println(l);
        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();
            }
        }
    }
}

五、标准输出流

1.PrintStream

​ 标准的字节输出流,默认输出到控制台,标准输出流不需要关闭,标准输出流其实就是经常使用的System.out.println(),使用代码如下:

public static void main(String[] args) {
    //联合起来写
    System.out.println("hello!");
    //分开写也可以
    PrintStream ps=System.out;
    ps.println("hello!");
}
1.1 改变标准输出位置

​ 可以改变标准输出位置到文件中,这个也是日志实现的原理,以下为改变输出到文件中的代码:

public static void main(String[] args) {
    //改变标准输出到文件中
    try {
        //将标准输出到控制台改到输出到"myFile"文件中
        System.setOut(new PrintStream(new FileOutputStream("myFile")));
        System.out.println("你好呀!");
        System.out.println("你是谁?");
        System.out.println("我是你爹!");
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
}
1.2 日志实现

​ 可以通过改变标准输出流的输出位置,实现日志功能,下面是日志实现及测试代码:

日志实现代码:

public static void log(String message){
    try {
        //将标准输出流指向一个文件
        PrintStream ps=new PrintStream(new FileOutputStream("log.txt",true));
        //改变输出方向
        System.setOut(ps);
        //记录当前时间
        Date nowDate=new Date();
        //改变时间格式
        SimpleDateFormat sdf=new SimpleDateFormat();
        String setString=sdf.format(nowDate);
        System.out.println(setString+":"+message);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
}

测试:

public static void main(String[] args){
    logger.log("调用了gc()方法,建议使用垃圾回收机制");
    logger.log("发生了类加载异常");
    logger.log("发生了空指针异常");
}

结果:
在这里插入图片描述

六、对象流

1.序列化和反序列化

​ 序列化:Serialize,java对象存储到文件中,将java对象的状态保存下来的过程。

​ 反序列化:DeSerialize,将硬盘上的数据重新恢复成到内存当中,恢复成java对象。

2.ObjectOutputStream

​ ObjectOutputStream是用来序列化的,在创建ObjectOutputStream时需要传参字节输出流,并且使用writeObject()方法对对象进行序列化时需要给自定义类型实现"Serializable"接口,这个接口里不用重写任何方法,只是为了得到序列化版本号。

​ 序列化之后不能直接用记事本打开文件,只能用对象输入字节流打开,使用方法如下:

public class Test01 {

public static void main(String[] args) throws Exception{
    //new对象时需要传入字节输出流对象
    ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("student"));
    //序列化
    oos.writeObject(new Student(11,"张三"));
    //刷新
    oos.flush();
    //关闭
    oos.close();
	}
}
	
class Student implements Serializable{
private int id;
private String name;

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

public Student() {
}

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

public String getName() {
    return name;
}

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

@Override
public String toString() {
    return "Student{" +
            "id=" + id +
            ", name='" + name + '\'' +
            '}';
	}
}
2.1 序列化多个对象

​ 当需要同时序列化多个对象时,可以将这些对象装在集合中,然后序列中集合即可,代码如下:

​ 【注意】:

​ Student类需要继承Serializable接口,这个接口中是个空的,也不用实现任何方法,但继承这个接口后会有一个序列码,JVM可以识别出来。

​ 要读取时按照正常流程读即可,读取时返回的Object类型就是存进去的集合类型,可以直接强转成List集合然后遍历。

public static void main(String[] args) throws Exception{
    //创建集合,将对象装进集合中
    List<Student> list=new ArrayList<>();
    list.add(new Student(18,"张三"));
    list.add(new Student(20,"李四"));
    list.add(new Student(25,"王麻子"));
    //创建对象输出字节流对象
    ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("students"));
    //开始序列化
    oos.writeObject(list);
    //刷新
    oos.flush();
    //关闭
    oos.close();
}
3.ObjectInputStream

​ ObjectInputStream是对硬盘上的文件进行反序列化,就是进行读操作,与ObjectInputStream使用方法相似。

​ 被ObjectOutputStream序列化之后的文件只能用ObjectOutputStream来读取,以下是使用方法:

public static void main(String[] args) throws Exception{
    //创建对象输入字节流
    ObjectInputStream ois=new ObjectInputStream(new FileInputStream("student"));
    Object o = ois.readObject();
    System.out.println(o);
}
4.transient关键字

​ 当不想让类中的某个元素被序列化的时候,可以给这个元素前加上"transient"关键字,这个关键字表示“游离的”,不参加序列化操作。

不参加序列化的元素在进行反序列化的时候,对象的这个属性会为null,即使存进去的时候这个属性是有值的。

5.序列化版本号

​ 上面提到参与序列化的自定义类型需要继承Serializable接口,但这个接口中没有任何方法,但JVM看到这个接口后会自动生成一个序列化版本号,但序列化版本号有什么作用呢,以下例子可以说明:

​ 十年前有一个实体类被序列化了,十年后需要优化程序,给实体类中添加了一个属性,然后进行反序列化会异常,十年之前生成的本地序列号和现在生成的序列号不同,报错如下:

java.io.InvalidClassException: com.drl.Connection.Student;
local class incompatible:
	stream classdesc serialVersionUID = -8551277354121190554(十年后)
    local class serialVersionUID = -8062692542557784925(十年前)

java语言中是采用什么机制区分类的?

​ 第一:首先通过类名来区分类,若类名不一样肯定不是一个类

​ 第二:如果类名一样,靠序列化版本号进行区分

【重要】:凡是一个类实现了Serializabel接口,建议给该类提供一个固定不变的序列化版本号,以后这个类即使改变了,但是版本号不变,java虚拟机会认为是一个类,就不会报错,可参考ArrayList:
在这里插入图片描述

七、File类常用方法

​ File类和四大家族没有关系,所以File类不能完成文件的读和写。

​ File是文件名和路径名的抽象表示形式。D:\work\blog,这是一个File对象,C:\Users\DRL\Desktop\test.txt,这也是一个File对象。一个File对象有可能是目录,也有可能是文件。

1.exist

​ 方法全称为:boolean exist(),判断File中的文件路径是否存在,存在返回true,不存在返回false,以下为使用方法:

public static void main(String[] args) {
    File file=new File("D:\\file");
    boolean exists = file.exists();
    System.out.println(exists);//此时文件中没有此路径,返回false
}
2.creatNewFile

​ 方法全称为:boolean creatNewFile(),在创建File对象时需要传入路径,在此路径下创建文件,若创建成功返回true,若创建失败返回false,代码和新建文件如下:

public static void main(String[] args) {
    File file=new File("D:\\file");
    boolean exists = file.exists();
    System.out.println(exists);//此时文件中没有此路径,返回false
    try {
        //在"D:/file"创建file文件
        boolean newFile = file.createNewFile();
        System.out.println(newFile);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

在这里插入图片描述

3.mkdir

​ 方法全称为:boolean mkdir(),在路径的位置上创建目录,创建成功返回true,创建失败返回false。

​ 【注意】:当此目录上有creatNewFile()方法创建的文件时,则不会创建文件夹目录。

public static void main(String[] args) {
    //创建File文件对象
    File file=new File("D://file");
    //在"D://file"位置上创建目录
    boolean mkdir = file.mkdir();
    System.out.println(mkdir);
}

在这里插入图片描述

4.mkdirs

​ 方法全程为:boolean mkdirs(),创建多层目录,需在路径中添加多层,如下代码和结果:

public static void main(String[] args) {
    //创建File文件对象
    File file=new File("D:/file/test1/test2");
    //在"D:/file"位置上创建目录
    boolean mkdirs = file.mkdirs();
    System.out.println(mkdirs);
}

在这里插入图片描述

5.getParent

​ 方法全程为:String getParent(),获取当前路径的父路径,使用方法如下:

public static void main(String[] args) {
    //创建File文件对象
    File file=new File("D:/file/test1/test2");
    //获取当前路径的父路径
    String parent = file.getParent();//D:\file\test1
    System.out.println(parent);
}
6.getAbsolutePath

​ 方法全称为:String getAbsolutePath(),获取当前文件的绝对路径,使用方法如下:

​ 【注意】:idea上的文件路径和所在的项目目录是一个级别的。

public static void main(String[] args) {
    //创建File对象
    File file=new File("myFile");
    //获取"myFile"的绝对路径
    System.out.println(file.getAbsolutePath());//E:\work\learnBySelf\collection\myFile
}
7.listFiles

​ 方法全称为:File[ ] listFiles(),获取当前目录下的所有子目录和文件,使用方法和结果如下:

public static void main(String[] args) {
    File file=new File("D:\\个人");
    File[] files = file.listFiles();
    for (File file1 : files) {
        System.out.println(file1.getAbsolutePath());
    }
}

输出结果:
在这里插入图片描述

原文件目录
在这里插入图片描述

八、IO与Properties联合使用

​ 可以用IO将普通文件中的配置属性读取出来,以下为使用方法:

public static void main(String[] args) throws Exception{
    //创建文件输出字节流对象(字符流也可以),test是放着配置信息的普通文本文件
    FileInputStream fis=new FileInputStream("test");
    //创建Properties对象
    Properties properties=new Properties();
    //使用load方法将文件中的数据加载到对象中来
    properties.load(fis);
    Object username = properties.get("username");
    System.out.println(username);
    String password = properties.getProperty("password");
    System.out.println(password);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值