一、FIle类
概念:代表物理盘符中的一个文件或者文件夹
常用方法:
FileFilter接口
FileFilter:文件过滤器接口
boolean accept(File pathname):当调用File乐熊的listFiles()方法时,支持传入FileFilter过滤接口实现类,对获取文件进行过滤,只有满足条件的文件才可出现在listFilters()的返回值中。
public void testio(File file){ File[] files = file.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { //过滤的条件 实现的功能 return false; } }); }
二、什么是io
生活场景:编辑一个文本文件,忘记ctrl+s,可能文件就白白编辑,当你电脑上插入一个U盘,可以拷贝视频、文件到电脑的硬盘中,那么数据都是在哪些设备上?键盘,内存,外接设备等等。
我们把数据的传输,可以看成是数据的流动,根据流动的方向,以内存为基准,分为输入input和输出output,即流向内存是输入流,流出内存是输出流。java中I/O操作主要是指使用java.io包下的内容,进行输入、输出操作。输入也称读取数据,输出也称写出数据。
三、IO分类
数据的流向分为输入流和输出流。
输入流:把数据从其他设备上读取到内存中的流。
输出流:把数据从内存中写出到其他设备上的流。
根据数据的类型分为:字节流和字符流。
字节流:以字节为单位,读写数据的流。
字符流:以字符为单位,读写数据的流。
输入流 | 输出流 | |
字节流 | 字节输入流InputStream | 字节输出流OutputStream |
字符流 | 字符输入流Reader | 字符输出流Writer |
四、字节流
一切皆为字节
一切文件数据(文本、图片、视频等)在存储是,都是以二进制数字的形式保存,是一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。
字节输出流
java.io.OutputStream抽象列是标识字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。
- public void close():关闭此输出流并释放与此流相关联的任何系统资源。
- public void flush():刷新此输出流并强制任何缓冲的输出字节被写出。
- public void write(byte b[]):将b.length字节从指定的字节数组写入此输出流。
- public void write(byte b[], int off, int len):从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。
- public abstract void write(int b):将指定的字节输出流。
FileOutputStream类
构造方法:
- public FileOutputStream(File file):创建文件输出流以写入由指定的File对象表示的文件。
- public FileOutputStream(String name):创建文件输出流以指定的名字写入文件。
1、写出字节:write(int b)方法,每次可以写出一个字节数据
2、写出字节数组:write(byte[] b),每次可以写出数组中的数据
3、写出指定长度字节数组:write(byte[] b,int off,int len),每次写出从off索引开始,len个字节
字节输入流
java.io.InputStream抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中,他定义了字节输入流的基本共性功能方法。
- public void close():关闭此输入流并释放与此相关联的任何系统资源。
- public abstract int read():从输入流读取数据的下一个字节。
- public int read(byte[] b):从输入流中读取一些字节数,并将他们存储到字节数组b中。
FileInputStream类
构造方法:
- public FileInputStream(File file):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的File对象file命名。
- public FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名。
1、读取字节:read()防范,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1。
2、使用字节数组读取:read(byte[] b),每次读取b的长度个字节到数组中,返回读取道德有效字节个数,读取到末尾时,返回-1。
五、字符流
字符输入流
java.io.Reader抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中,它定义了字符输入流的基本共性功能方法。
- public void close():关闭此流并释放与此流相关的任何系统资源。
- public int read():从输入流中读取一个字符。
- public int read(char[] cbuf):从输入流中读取一些字符,并将他们存储到字符数组cbuf中。
FileReader类
构造方法
- public FileReader(File file):创建一个新的FileReader,给定要读取的File对象。
- public FileReader(String fileName):创建一个新的FileReader,给定要读取的文件的名称。
构造时要使用系统默认的字符编码和默认字节缓冲区
1.字符编码:字节与字符的对应规则,Windows系统的中文编码默认是GBK编码表。idea中UTF-8
2.字节缓冲区:一个字节数组,用来临时存储字节数据。
- 1、读取字符:read防范,每次可以读取一个字符的数据,提升为int类型,读取到文件末尾,返回-1,循环读取。
- 2、使用字符数组读取:read(char[] cbuf),每次读取b的长度个字符到数组中,返回读取到的有效字符个数,读取到末尾时,返回-1。
字符输出流
java.io.Writer抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字符输出流的基本共性功能方法。
- public void write(int c):写入单个字符。
- public void write(char cbuf[]):写入字符数组。
- abstract public void write(char cbuf[], int off, int len):写入字符数组的某一部分,off数组的开始索引,len写入的字符个数。
- public void write(String str):写入字符串。
- public void write(String str, int off, int len):写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
- public void flush():刷新该流的缓冲。
- public void close():关闭此流,但要先刷新它。
FileWriter类
- public FileWriter(File file):创建一个新的FileWriter,给定要读取的File对象。
- public FileWriter(String fileName):创建一个新的FileWriter,给定要读取的文件的名称。
构造时使用系统默认的字符编码和默认字节缓冲区:
- 1、写出字符:writer(int b)方法,每次可以写出一个字符数据。
- 2、写出字符数组:writer(char[] cbuf)和writer(char[] cbuf,int off,int len),每次可以写出字符数组中的数据,用法类似FileOutStream
- 3、写出字符串:writer(String str)和writer(String str,int off,int len),每次可以写出字符串中的数据,更加方便。
因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中,但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush方法了。
六、缓冲流
概述
缓冲流也叫高效流,是对4个基本的FileXXX流的增强,所以也是4个流,根据数据类型分类:
- 字节缓冲流:BufferedInputStream,BufferedOutputStream
- 字符缓冲流:BufferedReader,BufferedWriter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
字节缓冲流
构造方法:
- public BufferedInputStream(InputStream in):创建一个新的缓冲输入流
- public BufferedOutputStream(OutputStream out):创建一个新的缓冲输出流
字符缓冲流
构造方法
- public BufferedReader(Reader in):创建一个新的缓冲输入流。
- public BufferedWriter(Writer out):创建一个新的缓冲输出流。
特有方法
字符缓冲流的基本方法与普通字符流调用方法一致
- BuffedReader:public String readLine():读一行文字。
- BufferedWriter:public void newLine():写一行行分隔符,由系统属性定义符号。
七、转换流
在idea中,使用FileReader读取项目中的文本文件。由于idea的设置,都是默认的UTF-8编码,所以没有任何问题,但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码。
那么如何解决这个问题?
InputStreamReader类
转换流java.io.InputStreamReader,是Reader的子类,是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符,他的字符集可以由名称指定,也可以接受平台的默认字符集。
- public InputStreamReader(InputStream in):创建一个使用默认字符集的字符流。
- public InputStreamReader(InputStream in, String charsetName):创建一个指定字符集的字符流。
八、序列化
概述
java提供了一种对象序列化的机制,用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息、字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据、对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象。
ObjectOutputStream类
java.io.ObjectOutputStream类,将java对象的原始数据类型写出到文件,实现对象的持久存储。
序列化操作
一个对象要想序列化,必须满足两个条件:
- 必须实现serializable接口。
- 必须保证其所有属性均可序列化。(transient修饰为临时属性,不参与序列化)
写出对象方法
public final void writeObject(Object obj):将指定的对象写出。
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Student implements Serializable {
public String name;
public String remark;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public Student() {
}
public Student(String name, String remark) {
this.name = name;
this.remark = remark;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", remark='" + remark + '\'' +
'}';
}
}
public class SerDemo {
public static void main(String[] args) throws IOException {
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("Student.txt"));
Student student = new Student("zhangsan", "ceshi");
outputStream.writeObject(student);
outputStream.close();
}
}
ObjectInputStream类
ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
反序列化操作
如果能找到一个对象的class文件,我们就可以进行反序列化操作,调用ObjectInputStream读取对象的方法。
public final Object readObject():读取一个对象。
public class SerDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("Student.txt"));
Student o = (Student) inputStream.readObject();
System.out.println(o);
inputStream.close();
}
}
注意:
对于JVM可以反序列化,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个ClassNOTFoundException异常。
当JVM反序列对象时,能找到class文件,但是class文件在学历恶化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException异常。
发生这个异常的原因在于:该类的序列版本号与从流中读取的类描述符的版本不匹配,serialVersionUID该版本的目的在于验证序列化的对象和对应类是否版本匹配。
serialVersionUID是一个非常重要的字段,因为Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同则认为一致,可以进行反序列化,否则就会出现序列化版本不一致的异常。
一般来说,定义serialVersionUID的方式有两种:
1.采用默认的1L,具体为private static final long serialVersionUID= 1L;
2.在可兼容的前提下,可以保留旧版本号,如果不兼容,或者想让它不兼容,就手工递增版本号。
根据类名、接口名、成员方法以及属性等来生成一个64位的哈希字段,例如 private static final long serialVersionUID=XXXL;
这种方式适用于如下场景:
1.开发者认为每次修改类后就需要生成新的版本号,不想向下兼容,操作就是删除原有serialVersionUID声明语句,在自动生成一下。
2.能够保证每次更改类结构后改变版本号,但还是要手工去生成。
九、Properties属性类
常用方法
- public Object setProperty(String key, String value):保存一对属性。
- public String getProperty(String key):使用此属性列表中指定的键搜索属性值。
- public Set<String> stringPropertyNames():所有键的名称的集合。
- public synchronized void load(InputStream inStream):从字节输入流中读取键值对。
public static void main(String[] args) throws IOException, ClassNotFoundException {
Properties properties = new Properties();
properties.setProperty("a","a");
properties.getProperty("a");
properties.load(new FileInputStream("db.properties"));
Set<String> strings = properties.stringPropertyNames();
for (String string : strings) {
String property = properties.getProperty(string);
System.out.println(property);
}
}
小贴士:文本中的数据,必须是键值对形式,可以使用空格、等号、冒号等符号分隔。