File类
- 是文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作。
- 是一个与系统无关的类,任何操作系统都可以使用这个类中的方法。
静态成员变量
- String pathSeparator 与 char pathSeparatorChar。与系统有关的路径分隔符(两个类型不一样)windows;分号,linux:冒号。
- String separator 与 char separatorChar。与系统有关的默认名称分隔符。windows \ 反斜杠,linux / 正斜杠。
绝对路径和相对路径
- 绝对路径:从盘符开始的路径,这是一个完整的路径。
- 相对路径:相对于项目目录的路径,这=是一个便捷的路径。
- 注意:路径不区分大小写,文件名称分隔符windows使用反斜杠,反斜杠是转义字符,两个反斜杠代表一个普通的反斜杠。
文件过滤器
- File类中有两个ListFiles重载的方法,方法的参数传递的就是过滤器。
- File[] listFiles(FileFilter filter):java.io.FileFilter接口:用于抽象路径名(File对象)的过滤器。包含抽象方法:boolean accept(File pathname) 。参数:File pathname:使用ListFiles方法遍历目录,得到的每一个文件对象。
- File[] listFiles(FilenameFilter filter):java.io.FilenameFilter 接口:实现此接口的类实力可用于过滤文件名。抽象方法:boolean accept(File dir, String name) 。参数:File dir,File构造方法中传递的被遍历的目录;String name,使用ListFiles方法遍历目录,获取的每一个文件/文件夹的名称。
- 注意:两个过滤器接口都没有实现类,需要自己写实现类,重写过过滤方法accept,在里面定义过滤规则。
过滤器原理
- File对象调用listFiles方法做了3件事,一:对构造方法中传递的目录进行遍历,获取目录中的每一个文件/文件夹,封装为File对象;二:调用参数传递的过滤器中的方法accept;三:把遍历得到的每一个File对象,传递进accpet方法的参数pathname。
- accpet方法返回值是布尔值。为true则会把传递过来的File对象保存到File数组中;为false则不会保存到File数组中。
IO分类
- 输入流 :把数据从 其他设备 上读取到 内存 中的流。
- 输出流 :把数据从 内存 中写出到 其他设备 上的流。
- 字节流 :以字节为单位,读写数据的流。
- 字符流 :以字符为单位,读写数据的流。
顶级父类
* | 输入流 | 输出流 |
---|---|---|
字节流 | 字节输入流 InputStream | 字节输出流 OutputStream |
字符流 | 字符输入流 Reader | 字符输出流 Writer |
OutputStream字节输出流
- 是抽象类,表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。
- 写入数据(内存到硬盘)原理:java程序–>JVM–>os(操作系统)–>os调用写数据方法–>把数据写入到文件中
FileOutputStream类
OutputStream其中一个子类。文件字节输出流。
使用步骤
- 创建一个FileOutputStream对象,构造方法中传递写入数据的目的地。
- 调用FileOutputStream对象中的write方法,把数据写入到文件中。
- 释放资源。(流使用会占用一定的内存,使用完毕要把内存清空,提供程序的效率)
注意
- 写数据的时候会把十进制的整数转化为二进制的整数。硬盘中存储的数据都是字节,1字节=8比特位(10101010)。
- 字符串中方法getBytes()可以快速获取字节数组。
- 如果读写流都在,先释放写的,后关闭读的。如果写完了,肯定读取完毕了。
数据追加续写
构造方法中存在参数boolean append,true表示追加数据, false 表示清空原有数据。
换行写
Windows系统里,换行符号是 \r\n 。linux里 /n。mac里 /r。
InputStream字节输入流
- 是抽象类,表示字节输入流的所有类的超类,可以读取字节信息到内存中。
- 写入数据(硬盘到内存)原理:java程序–>JVM–>os(操作系统)–>os调用读取数据方法–>读取文件
FileInputStream类
InputStream其中一个子类。文件字节输入流。
使用步骤
- 创建FileInputStream对象,构造方法中绑定要读取的数据源。
- 使用FileInputStream对象中的read方法,读取文件。
- 释放资源。
注意
read方法读取到-1表示结束。
// 循环读取
while ((b = fis.read())!=‐1) {
System.out.println((char)b);
}
Reader字符输入流
- 是抽象类,表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。
- 字节流遇到中文字符时,可能不会显示完整的字符,因为一个中文字符可能占用多个字节存储。字符流类,以字符为单位读写数据,专门用于处理文本文件。
FileReader类
InputStreamReader的子类,InputStreamReader继承Reader。文件字符输入流。
使用步骤
- 创建FileReader对象,构造方法中绑定要读取的数据源。
- 调用FileReader对象中的read方法,读取文件。
- 释放资源。
Writer字符输出流
是抽象类,表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。
FileWriter类
OutputStreamWriter的子类,OutputStreamWriter继承Writer。文件字符输出流。
使用步骤
- 创建FileWriter对象,构构造方法中绑定要写入数据的目的地。
- 调用FileWriter对象中的write方法,把数据写入到内存缓冲区中。(字符转换为字节的过程)
- 使用FileWriter中的flush方法,把内存缓冲区中的数据刷新到文件中。
- 释放资源。(会先把内存缓冲区中的数据刷新到文件中)
关闭和刷新
- flush :刷新缓冲区,流对象可以继续使用。
- close :先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
IO异常的处理
JDK1.7之前使用 try…catch…finally 代码块处理
// 声明变量
FileWriter fw = null;
try {
//创建流对象
fw = new FileWriter("fw.txt");
// 写出数据
fw.write("程序员");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fw != null) {
fw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
JDK7优化后的 try-with-resource 语句
try (创建流对象语句,如果多个使用';'隔开) {
// 读写数据
} catch (IOException e) {
e.printStackTrace();
}
JDK9中 try-with-resource 的改进,对于引入对象的方式,支持的更加简洁。
A a = new A();
B b = new B();
try(a, b) {
// 可能产生异常的代码
}
属性集
- java.util.Properties 继承于 Hashtable,实现了Map接口。
- Properties 表示一个持久的属性集。可保存在流中或者从流中加载。
- Properties 每个键及其对应值都是一个字符串。
基本方法
- Object setProperty(String key, String value) : 保存一对属性。相当于put方法。
- String getProperty(String key) :通过key找到value值。相当于get(key)方法。
- Set<String> stringPropertyNames() :所有键的名称的集合。相当于keySet()方法。
与流相关的方法
- Properties 集合是唯一一个和IO流相结合的集合。
- 可以使用Properties集合中的stroe方法,把集合中的临时数据,持久化写入到硬盘中存储。
- 可以使用Properties集合中的load方法,把硬盘中保存的文件(键值对),读取到集合中使用。
- void stroe(流,String comments):comments注释,不能使用中文会产生乱码。中文文件,流建议使用字符流。
- void load(流):加载的文件中,键值对形式,默认的链接符号可以使用=,空格或其他符号;可以使用#进行注释;键与值默认都是字符串,不需要再加引号。
缓冲流
- 缓冲流,也叫高效流。基本原理是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
- 字节缓冲流: BufferedInputStream ,BufferedOutputStream
- 字符缓冲流: BufferedReader , BufferedWriter
BufferedOutputStream类
字节缓冲输出流BufferedOutputStream继承OutputStream。
使用步骤
- 创建FileOutputStream对象,构造方法中绑定要输出的目的地。
- 创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream对象的效率。
- 使用BufferedOutputStream对象中的write方法,把数据写入到内部缓冲区中。
- 使用BufferedOutputStream对象中的flush方法,把内部缓冲区的数据刷新到文件中。
- 释放资源。(会先调用flush方法刷新数据,上一步可以省略)
BufferedInputStream类
字节缓冲输入流BufferedInputStream继承InputStream。
使用步骤
- 创建FileInputStream对象,构造方法中绑定要读取的数据源。
- 创建BufferedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象的效率。
- 使用BufferedInputStream对象中的read方法,读取文件。
- 释放资源。
BufferedWriter类
字符缓冲输出流BufferedWriter继承Writer。
特有方法
void newLine():写入一个行分隔符,会根据不同操作系统,获取不同的行分隔符。
使用步骤
- 创建字符缓冲输出流BufferedWriter对象,构造方法中传递字符输出流FileWriter。
- 使用字符缓冲输出流BufferedWriter对象中的write方法,把数据写入到内存缓冲区中。
- 使用字符缓冲输出流BufferedWriter对象中的flush方法,把内存缓冲区的数据刷新到文件中。
- 释放资源。
BufferedReader类
字符缓冲输入流BufferedReader继承Reader。
特有方法
- String readLine():读取一个文本行。读取一行数据。
- 行的终止符:通过下列字符之一即可任维某行已终止:换行(‘\n’)、回车(‘\r’)或回车后直接跟着换行(\r\n)。
- 返回值:包含该行内容的字符串,不包含任何终止符,如果已到达流末尾,则返回null。
使用步骤
- 创建字符缓冲输入流BufferedReader对象,构造方法中传递字符输入流FileReader。
- 使用字符缓冲输入流BufferedReader对象中的read/readLine方法读取文本。
- 释放资源。
字符编码和字符集
- 字符编码 Character Encoding : 就是一套自然语言的字符与二进制数之间的对应规则。
- 字符集 Charset :也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。常见字符集有ASCII字符集、GBK字符集、Unicode字符集等。
编码引出的问题
于Windows系统的默认是GBK编码,用UTF-8 编码读取就会出现乱码。所以使用转换流来解决。
OutputStreamWriter类
- 转换流OutputStreamWriter继承Writer,直接已知子类是FileWriter。
- 是从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。(编码)
使用步骤
- 创建OutputStreamWriter对象,构造方法中传递字节输出流FileOutputStream和指定的编码表名称。(不指定编码表名称默认是UTF-8)
- 使用OutputStreamWriter对象中的write方法,把字符转换为字节存储缓冲区中。(编码)
- 使用OutputStreamWriter对象中的flush方法,把内存缓冲区的字节刷新到文件中。(使用字节流写字节的过程)
- 释放资源。
InputStreamReader类
- 转换流InputStreamReader继承Reader,直接已知子类是FileReader。
- 是从字节流到字符流的桥梁。读取字节,并使用指定的字符集将其解码为字符。(解码)
使用步骤
- 创建InputStreamReader对象,构造方法中传递字节输入流FileInputStream和指定的编码表名称。(不指定编码表名称默认是UTF-8)
- 使用InputStreamReader对象中的read方法读取文件。
- 释放资源。
注意
构造方法中指定的编码表名称要和文件的编码相同,否则会发生乱码。
序列化
- 对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
- 反序列化。 对象的数据、对象的类型和对象中存储的数据 信息,都可以用来在内存中创建对象。
ObjectOutputStream类
对象的序列化流,继承OutputStream。把对象意流的方式写入到文件中保存。
特有成员方法
void writeObject(Object obj):将指定的对象写入ObjectOutputStream。
使用步骤
- 创建ObjectOutputStream对象,构造方法中传递字节输出流FileOutputStream。
- 使用ObjectOutputStream对象中的writeObject方法,把对象写入到文件中。
- 释放资源。
注意
- 对象类需实现Serializable接口以启用其序列化功能。未实现此接口将无法使其任何方法序列化或反序列化。
- Serializable接口也叫标记型接口,进行序列化和反序列化的时候,检测类上有这个标记才会进行,没有就会抛出NotSerialzableException异常。
ObjectInputStream类
对象的反序列化流,继承InputStream。将序列化的原始数据恢复为对象。
特有成员方法
Object readObject():从ObjectOutputStream读取对象。
使用步骤
- 创建ObjectOutputStream对象,构造方法中传递字节输入流FileInputStream。
- 使用ObjectOutputStream对象中的readObject方法读取保存对象的文件。
- 释放资源。
- 使用读取出来的对象
注意
- readObject()方法声明抛出ClassNotFoundException(class文件找不到异常)。反序列化前提是,类必须实现Serializable;必须存在类对应的class文件。
- 反序列化时,能找到class文件,但class文件再序列化对象之后发生了修改,也会反序列化失败,抛出 InvalidClassException 异常。
- 修改序列化对象解决:手动添加一个序列号,无论是否对类进行修改,都不生成新的序列号。如:修饰符 static final long serialVersionUID = 1L;
transient关键字
瞬态关键字,修饰的成员变量不能被序列化。
static关键字
静态关键字,静态优先于非静态加载到内存中(静态优先于对象进入到内存中)。被static修饰的成员变量不能被序列化,序列化的都是对象。
打印流
能够方便地打印各种数据类型的值,是一种便捷的输出方式。
PrintStream类
继承OutputStream。
特点
- 只负责数据的输出,不负责数据 的读取。
- 与其他输出流不同,PrintStream永远不抛出IOExcption。
- 特有方法print,println 输出任意类型的值。
注意
- 使用继承自父类的write方法写数据,那么查看输出时候会查询编码表。
- 使用自己特有的方法print,println写数据,写的数据原样输出。
- System.out.println() 输出再控制台。使用System.setOut(PrintStream) 方法,会改变输出语句的目的地,改为参数中传递的打印流的目的地。
TCP通信程序
- TCP通信能实现两台计算机之间的数据交互,通信的两端,要严格区分为客户端(Client)与服务端(Server)。
- 服务端程序,需要事先启动,等待客户端的连接。
- 客户端主动连接服务器端,连接成功才能通信。服务端不可以主动连接客户端。
Socket类
该类实现客户端套接字,套接字指的是两台设备之间通讯的端点。包含了IP地址和端口号的网阔单位。
实现步骤
- 创建一个客户端Socket对象,构造方法方法绑定服务器的IP地址和端口号。
- 使用Socket对象中的方法getOutputStream()获取网络字节输出流OutputStream对象。
- 使用网络字节输出流OutputStream对象中的write方法,给服务器发送数据。
- 使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象。
- 使用网络字节输入流InputStream对象中的read方法,读取服务器回写的数据。
- 释放资源。(Socket)
注意
- 客户端与服务器端进行交互,必须使用Socket中提供的网络流,不能使用自己创建的流对象。
- 创建客户端对象Socket的时候,会去请求服务器和服务器进行3次握手建立连接通路。如果服务器没有启动,就会抛出异常;如果服务器已经启动,可以进行交互。
阻塞状态
- 当服务器网络字节输入流InputStream对象中read方法一直未读取到结束标记,就会进入阻塞状态。
- 需要在客户端,使用Socket对象的shutdownOutput()方法,禁用此套接字的输出流。
ServerSocket类
该类实现了服务器套接字。接受客户端的请求,读取客户端发送的数据,回写数据给客户端。
实现步骤
- 创建服务器ServerSocket对象和系统要指定的端口号。
- 使用ServerSocket对象中accept方法,获取请求的客户端对象Socket。
- 使用Socket对象中getInputStream()方法获取网络字节输入流InputStream对象。
- 使用网络字节输入流InputStream对象中read方法,读取客户端发送的数据。
- 使用Socket对象中getOutputStream()方法获取网络字节输出流OutputStream对象。
- 使用网络字节输出流OutputStream对象中write方法,给客户端回写数据。
- 释放资源。(Socket,ServerSocket)