文章目录
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的抽象方法
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的抽象方法
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 序列化过程
-
需要序列化的对象所属的类实现java.io.Serializable接口, Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出 NotSerializableException ;
此处先说明实现Serializable接口以序列化,另一种实现Externalizable接口的方法在后面说。
-
需要序列化的对象所属的类的所有属性必须是可序列化的(如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用 transient 关键字修饰,以完成部分属性的可序列化);
-
使用对象字节输出流写出指定对象。
4.4 反序列化过程
如果能找到一个对象的class文件,我们可以进行反序列化操作,调用 ObjectInputStream 读取对象的方法。
注意:
-
如果找不到该类的class文件,则抛出一个 ClassNotFoundException 异常;
-
当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个 InvalidClassException 异常。
-
InvalidClassException 异常的原因:
- 该类的序列版本号与从流中读取的类描述符的版本号不匹配
- 该类包含未知数据类型
- 该类没有可访问的无参数构造方法
-
Serializable 接口给需要序列化的类,提供了一个序列版本号。 serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。
4.5 实现部分属性的序列化和反序列化的方法
- 使用 transient 关键字修饰不想序列化的属性
- 使用 static 关键字修饰不想序列化的属性
- 在想要序列化的类中添加两个private void方法:writeObject方法和readObject方法(在Serializable接口的定义、ObjectStreamClass类(用于分析JVM中加载的序列化类的序列化特征,它的lookup方法可以获取到被序列化的类的信息)的源码中:对象流在序列化对象的时候会先去找我们的这两个私有方法,优先调用我们的,我们的这两个私有方法可以决定序列化哪些属性,注意的是此时序列化和反序列化的属性要一一对应);
- 目标类实现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