File类、IO流、Properties、序列化和try-with-resouces的知识点笔记!

文章目录

1. java.io.File

1.1 File类的概念

​ java.io.File类是文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作。java把电脑中的文件和文件夹(目录)封装成了一个File类,我们可以使用File类对文件和文件夹进行操作

​ File类是一个与操作系统无关的类,任何操作系统都可以使用这个类的方法。

​ 重点记住三个单词:(1)file文件、(2)directory文件夹/目录、(3)path路径

1.2 File的常用构造方法

  • File(File parent, String child)

    ​ 从父抽象路径名和子路径名字符串创建新的 File实例。

  • File(String pathname)

    ​ 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。

  • File(String parent, String child)

    ​ 从父路径名字符串和子路径名字符串创建新的 File实例。

1.3 创建一个File类对象的注意事项

  • pathname是字符串的路径名称,可以是相对路径也可以是绝对路径,路径的真假情况不考虑,这里只是把字符串封装成一个File对象;

  • parent是父路径,child是子路径,这样分开使用的好处就是使用起来非常灵活,父路径和子路径都可以变化;

  • 如果parent的数据类型是File类,使得使用灵活之外,因为父路径是File类型的,所以可以使用File的方法对路径进行一些操作,再使用路径创建对象。

1.4 File类的静态成员变量(分隔符)

​ 这样可以让我们的路径不会被写死,不然在不同操作系统上运行的时候会出错。(路径是不区分大小写的

  • static String pathSeparator

    ​ 与系统相关的路径分隔符,为方便起见,表示为字符串。(Windows下是分号;,Linux下是冒号:)

  • static char pathSeparatorChar

    ​ 与系统相关的路径分隔符

  • static String separator

​ 系统相关的默认名称分隔符,为方便起见,表示为字符串。

  • static char separatorChar

​ 系统相关的默认名称分隔符(Windows就是反斜杠“\”,Linux就是正斜杠“/”)

注意:不同操作系统的换行符号也不同

  • windows:\r\n
  • Linux:/n
  • mac:/r

1.5 File类的常用方法

1.5.1 获取
  • public String getAbsolutePath():

    ​ 无论构造方法使用的是相对路径还是绝对路径,这个方法都是返回获取此File的绝对路径

  • public String getPath():

    ​ 这个方法就是获取构造方法中的路径,创建对象时使用的是相对路径,那么调用这个方法的时候获取得到的也是相对路径,File类重写了toString方法,toString方法其实就是在调用getPath方法

  • public String getName():

    ​ 这个方法就是获取构造方法传递路径的结尾部分(文件/文件夹),其实就是获取返回路径中最后一个文件/文件夹,如果是路径是盘符的话就是空;

  • public long length():

    ​ 这个方法就是就是返回获取此File表示的文件的长度,以字节为单位,注意不能获取文件夹的大小(文件夹无大小的概念),如果路径不存在,返回0。

  • public File[] listFiles():

    ​ 这个方法就是就是返回获取此路径下的所有文件(只是一层的,如果有文件夹,这个文件夹下的文件不会被返回)。

1.5.2 判断
  • public boolean exists():

    ​ 此File表示的文件或目录是否实际存在

  • public boolean isDirectory():

    ​ 此File表示的是否是目录

  • public boolean isFile():

    ​ 此File表示的是否是文件

1.5.3 创建与删除
  • public boolean creatNewFile:

    ​ 文件存在则不会创建,返回false,文件不存在则创建文件,返回true,创建文件的路径必须存在,否则抛出异常;(这个方法声明抛出了IOException,要么throws,要么try/catch)

  • public boolean delete:

    ​ 文件/文件夹删除成功返回true,如果文件夹有内容就不会删除返回false,构造方法中路径不存在的话也不删除并返回false;(delete方法是直接在硬盘中删除文件/文件夹,不走回收站,删除要谨慎。

  • public boolean mkdir:

    ​ 文件夹不存在则创建一个,返回true,反之不创建,返回false,如果给出的路径是不存在的也返回false,这个方法只能创建单级文件夹

  • public boolean mkdirs:

    ​ 文件夹不存在则创建一个,返回true,反之不创建,返回false,如果给出的路径是不存在的也返回false,这个方法既可以创建单级文件夹,也可以创建多级文件夹

  • public boolean reNameTo(File dest):

    ​ 把这个文件/文件夹变成dest,可以改名,可以换路径。比如说:我们把一个D盘下的LOL.exe,改到C盘下的LOL2.exe,就可以用这个方法。


2 IO流

2.1 IO的概念

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

JAVA中的I/O操作主要是指使用java.io包下的内容,进行输入输出操作:

​ **输入也叫做读取数据:**java程序 -> JVM -> OS -> OS调用读数据的方法 -> 数据读入内存

​ **输出也叫做写出数据:**java程序 -> JVM -> OS -> OS调用写数据的方法 -> 数据从内存写出

2.2 IO的分类(顶级父类,抽象类)

​ 一切皆字节,计算机中的数据(文本、图片、视频、音乐……)都是以二进制形式存储的。在数据传输时,也都是以二进制形式存储的。

​ 后续学习的任何流,在传输时底层都是二进制,字符流也来自于字节流,只不过对字节流做了一些处理。

  • 字节流

    • 字节输入流 InputStream
    • 字节输出流 OutputStream
  • 字符流

    • 字符输入流 Reader
    • 字符输出流 Writer

2.3 字节流

​ 一切皆字节,计算机中的数据(文本、图片、视频、音乐……)都是以二进制形式存储的。

​ 在数据传输时,也都是以二进制形式存储的。

2.3.1 字节输入流 InputStream

​ 这是一个超类,同时是一个抽象类,因此使用它必须使用其子类。在读取多个字节数据的时候,可以使用byte数组,这样可以起到缓冲作用,存储每次读取到的多个字节,数组的长度一般定义为1024字节或者1024的整数倍,也即是1KB,返回值是有效读取的字节个数。

2.3.1.1 InputStream的抽象方法

C:\Users\82169\AppData\Roaming\Typora\typora-user-images\image-20210313142602879.png

2.3.1.2 FileInputStream
2.3.1.2.1 FileInputStream的概念

​ java.io.FileInputStream是字节输入流的一个直接子类,用得特别多,用于对文件数据的读入数据。

​ 使用这个子类创建对象的时候,要注意可能会抛出的FileNotFoundException,所以要try/catch或者throws。

2.3.1.2.2 FileInputStream的常用构造方法
  • FileInputStream(File file)

    ​ 通过打开与实际文件的连接来创建 FileInputStream,该文件由文件系统中的File对象 file命名。

  • FileInputStream(String name)

    ​ 通过打开与实际文件的连接来创建 FileInputStream,该文件由文件系统中的路径名name命名。

2.3.1.2.3 FileInputStream的常用方法
  • public int read()

    ​ 从此输入流中读取一个字节的数据,返回类型是int,但是只有低八位有效

  • public int read(byte[] b)

    ​ 将b.length字节的数据从指定的字节数组b里写入此输入流,并返回读取字节数。

2.3.2 字节输出流 OutputStream
2.3.2.1 OutputStream的抽象方法

在这里插入图片描述

2.3.2.2 FileOutputStream
2.3.2.2.1 FileOutputStream的概念

​ java.io.FileOutputStream是字节输出流的一个直接子类,用得特别多,用于对文件的写出数据。

​ 使用这个子类创建对象的时候,要注意可能会抛出的FileNotFoundException,所以要try/catch或者throws。

2.3.2.2.2 FileOutputStream的常用构造方法
  • FileOutputStream(File file)

    ​ 创建文件输出流以写入由指定的 File对象表示的文件,这个File对象不存在会被创建,但是权限问题,不一定能创建

  • FileOutputStream(File file, boolean append)

    ​ 创建文件输出流以写入由指定的 File对象表示的文件,是否追加。

  • FileOutputStream(String name)

    ​ 创建文件输出流以写入具有指定名称的文件,这个File对象不存在会被创建,但是权限问题,不一定能创建

  • FileOutputStream(String name, boolean append)

    ​ 创建文件输出流以写入具有指定名称的文件 ,是否追加。

2.3.2.2.3 FileOutputStream的常用方法
  • public void write(byte[] b)

    ​ 将b.length字节的数据从指定的字节数组b里写入此输出流。

    (如果一次写出多个,如果第一个字节是正数:0~127,那么会显式地查询ASCII表;如果是负数,那么第一个字节和第二个字节就会组成一个中文显示,查询系统默认的码表GBK)

2.4 字符流

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

字符流并不能解决因为编码格式而导致的乱码问题,我们还是需要自己设置。

2.4.1 字符输入流 Reader
2.4.1.1 Reader的抽象方法

image-20210313194603215.png

2.4.1.2 FileReader
2.4.1.2.1 FileReader的概念

​ 文件字符输入流是Reader的一个子类,作用是把硬盘文件中的数据以字符的方式读取到内存中。

2.4.1.2.2 FileReader的常用构造方法
  • FileReader(File file)

    绑定要读取的文件,在 File读取时创建一个新的 FileReader 。

  • FileReader(File file, Charset charset)

    创建一个新的FileReader ,给出File读取和charset 。

  • FileReader(String fileName)

    给定要读取的文件的名称,创建一个新的FileReader 。

  • FileReader(String fileName, Charset charset)

    给定要读取的文件的名称和采用的字符集 ,创建一个新的FileReader 。

2.4.1.2.3 FileReader的常用方法
  • int read()

    从此输入流中读取一个字符的数据并返回。

  • int read(char[] cbuf)

    从此输入流中读取cbuf.length个字符的数据存放到这个数组里面,并返回读取字符的个数 。

2.4.2 字符输出流 Writer
2.4.2.1 Writer的抽象方法

在这里插入图片描述

2.4.2.2 FileWriter
2.4.2.2.1 FileWriter的概念

​ 文件字符输出流是Writer的一个子类,作用是把内存中字符数据写入到文件中。

2.4.2.2.2 FileWriter的常用构造方法

​ 这里只给出了第一个参数是文件表示的File类对象的构造方法,传入文件的路径字符串的也行,这两种是配套出现的。

  • FileWriter(File file)

    给 File写一个 FileWriter ,使用平台的 default charset

  • FileWriter(File file, boolean append)

    在给出要写入的 FileWriter下构造 File ,并使用平台的 default charset构造一个布尔值,指示是否附加写入的数据。

  • FileWriter(File file, Charset charset)

    构造一个FileWriter给予File编写和charset 。

  • FileWriter(File file, Charset charset, boolean append)

    构造FileWriter给出File写入, charset和一个布尔值,指示是否附加写入的数据。

2.4.2.2.3 FileWriter的常用方法
  • void flush()

    刷新流。

  • void write(char[] cbuf, int off, int len)

    写一个字符数组的一部分。

  • void write(int c)

    写一个字符。

  • void write(String str, int off, int len)

    写一个字符串的一部分

2.4.2.2.4 关闭(close)和刷新(flush)的区别

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

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

2.5 转换流

将字节流装饰成字符流(使用了装饰者设计模式)。

2.5.1 InputStreamReader

​ 通过构造方法new一个InputStreamReader对象,然后参数为要转换的字节输入流、要读入字符的编码格式(可以不给),即可将字节输入流转换成字符输入流。

2.5.2 OutputStreamWriter

​ 通过构造方法new一个OutputStreamWriter对象,然后参数为要转换的字节输出流、要读出字符的编码格式(可以不给),即可将字节输出流转换成字符输出流。

2.6 打印流

2.6.1 打印流的概念

​ 平时我们在控制台打印输出,是调用 print 方法和 println 方法完成的,这两个方法都来自于 java.io.PrintStream 类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式。

2.6.2 PrintOutputStream

​ 用法和FileOutputStream没什么区别。

2.6.3 PrintWriter

​ PrintWriter可以看作是一个字符输出流(可看成也是一个包装类,带缓冲区的,包装成了BufferedWriter) 。

​ 它可以设置自动刷新,使用println(xxx)方法,自动输出到目的地,默认是不自动刷新的

2.7.缓冲流

2.7.1 缓冲流的概念

​ 缓冲流,也叫高效流,是对4个基本的 FileXxx 流的增强,所以也是4个流,按照数据类型分类:

  • 字节缓冲流: BufferedInputStream , BufferedOutputStream

  • 字符缓冲流: BufferedReader , BufferedWriter

​ 缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小(8k)的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。

2.7.2 字节缓冲流
  • public BufferedInputStream(InputStream in)

    创建一个新的缓冲输入流。

  • public BufferedOutputStream(OutputStream out)

    创建一个新的缓冲输出流。

  • public BufferedInputStream(InputStream in, int size)

    创建一个新的具有指定缓冲区大小的缓冲输入流。

  • public BufferedOutputStream(OutputStream out, int size)

    创建一个新的具有指定缓冲区大小的缓冲输出流。

2.7.3 字符缓冲流
2.7.3.1 字符缓冲流的构造方法
  • public BufferedReader(Reader in)

    创建一个 新的缓冲输入流。

  • public BufferedWriter(Writer out)

    创建一个新的缓冲输出流。

  • BufferedReader(Reader in, int sz)

    创建使用指定大小的输入缓冲区的缓冲字符输入流。

  • public BufferedWriter(Writer out, int sz)

    创建使用指定大小的的输入缓冲区的缓冲字符输出流。

2.7.3.2 字符缓冲流的特有方法
  • BufferedReader

    • public String readLine()

      读一行文字。

  • BufferedWriter

    • public void newLine()

    写一行行分隔符,由系统属性定义符号

2.8 字符流和字节流的注意事项

  • 一般字节流是直接与数据产生交互,而字符流在与数据交互之前要经过一个缓冲区
  • Writer类或其子类需要flush,Reader类没有
  • 带缓冲区的输出流,如果缓冲区满了就会自动flush;
  • 字节流只有非Buffered的输出流才不需要调用flush()
  • 字节流可以处理一切文件,而字符流只能处理纯文本文件;
  • PrintWriter如果设置了自动刷新,也不需要flush,不然就需要;
  • 所有带缓冲区的IO流,默认的缓冲区大小是8K

3. Properties

​ Properties是Hashtable的一个子类,既属于IO范畴,又属于集合范畴。

​ 它的使用也是采用了键值对的存取方式

3.1 Properties的构造方法
  • Properties()

    创建一个没有默认值的空属性列表,默认大小是8。

  • Properties(int initialCapacity)

    创建一个没有默认值的空属性列表,并且初始大小容纳指定数量的元素,而无需动态调整大小。

  • Properties(Properties defaults)

    创建具有指定默认值的空属性列表。

3.2 Properties的常用方法
  • void load(InputStream inStream)

    从输入字节流中读取属性列表(键和元素对)。

  • void load(Reader reader)

    以简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。

  • store(OutputStream out, String comments)

    将此 Properties表中的此属性列表(键和元素对)以适合使用 load(InputStream)方法加载到 Properties表的格式写入输出流。

  • void store(Writer writer, String comments)

    将此 Properties表中的此属性列表(键和元素对)以适合使用 load(Reader)方法的格式写入输出字符流。


4. 序列化技术

4.1 序列化的概念

​ Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据 、 对象的类型和对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。 反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。 对象的数据 、 对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HgkWdNAM-1616252285512)(C:\Users\82169\AppData\Roaming\Typora\typora-user-images\image-20210313220211888.png)]

4.2 对象流
4.2.1 对象流的概念

​ 操作对象,将JAVA对象的原始数据类型从文件中读取出来或者是保存到文件中等,实现对象的持久化。

4.2.2 ObjectOutputStream的构造方法和写出对象
  • public ObjectOutputStream(OutputStream out )

    创建一个指定OutputStream的ObjectOutputStream。

  • public final void writeObject (Object obj)

    将指定的对象写出。

4.2.3 ObjectInputStream的构造方法和读取对象
  • public ObjectInputStream(InputStream in)

    创建一个指定InputStream的ObjectInputStream。

  • public final Object readObject ()

    读取一个对象。

4.3 序列化过程
  1. 需要序列化的对象所属的类实现java.io.Serializable接口, Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出 NotSerializableException ;

    此处先说明实现Serializable接口以序列化,另一种实现Externalizable接口的方法在后面说。

  2. 需要序列化的对象所属的类的所有属性必须是可序列化的(如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用 transient 关键字修饰,以完成部分属性的可序列化);

  3. 使用对象字节输出流写出指定对象。

4.4 反序列化过程

如果能找到一个对象的class文件,我们可以进行反序列化操作,调用 ObjectInputStream 读取对象的方法。

注意:

  1. 如果找不到该类的class文件,则抛出一个 ClassNotFoundException 异常;

  2. 当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个 InvalidClassException 异常。

  3. InvalidClassException 异常的原因:

    1. 该类的序列版本号与从流中读取的类描述符的版本号不匹配
    2. 该类包含未知数据类型
    3. 该类没有可访问的无参数构造方法
  4. Serializable 接口给需要序列化的类,提供了一个序列版本号。 serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配

4.5 实现部分属性的序列化和反序列化的方法
  1. 使用 transient 关键字修饰不想序列化的属性
  2. 使用 static 关键字修饰不想序列化的属性
  3. 在想要序列化的类中添加两个private void方法:writeObject方法和readObject方法(在Serializable接口的定义、ObjectStreamClass类(用于分析JVM中加载的序列化类的序列化特征,它的lookup方法可以获取到被序列化的类的信息)的源码中:对象流在序列化对象的时候会先去找我们的这两个私有方法,优先调用我们的,我们的这两个私有方法可以决定序列化哪些属性,注意的是此时序列化和反序列化的属性要一一对应);
  4. 目标类实现Externalizable接口(Externalizable接口继承自Serializable接口),然后重写writeObject方法和readObject方法。

​ 定制序列化的部分过程如下,类似的可以举一反三。
在这里插入图片描述


5. try-with-resources

  • JDK 1.7:

    ​ 可以把需要释放资源的对象(用完需要close的,比如io流),放到try括号里去new。能这样去做的,即try后面括号里的资源必须实现了Closeable接口或者是AutoCloseable接口,也就是要保证必须含有close方法

    (注意:这样有个问题,如果是这个资源是传过来的就不方便使用了,或者是接下来还有继续用、不想直接关闭的)

  • JDK 1.9:

    ​ 对其进行了优化,只需要将需要用完close的资源对象的字面量(对象名)放到try后的小括号即可,如果是多个资源对象就用分号隔开。

(1) catch 块中,“看不到”(作用域问题) try-with-recourse 声明中的变量。
(2) try-with-recourses 中,try 块中抛出的异常,在 e.getMessage() 可以获得,而调用 close() 方法抛出的异常在e.getSuppressed() 获得。
(3)try-with-recourse 中定义多个变量时,由反编译可知,关闭的顺序是从后往前。


详细了解try-with-resources:https://blog.csdn.net/weixin_40255793/article/details/80812961

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值