I/O概述
I/O是Input/Output的缩写,表示输入输出。对于内存来说,从内存中取出数据写入到磁盘中的操作是输出,也就是写。从磁盘中读取数据到内存中是输入的操作,也就是读。
I/O流根据操作数据的最小单位,分为字符流和字节流。又可以根据是否直接对文件资源进行读写操作,分为节点流和处理流。
下面以java.io包为基础,学习I/O流的内容。
1. 继承结构
2.类的概述
2.1 File类
File类是对文件和目录的抽象。它可以用来表示一个文件或路径。I/O流操作目标就是系统中的文件。
**
* Description:File类
* 概述:File类是对文件和路径的抽象。
* 1.静态成员。
* pathSeperator:路径分隔符。windows:分号; linux:冒号:
* seperator:名称分隔符。windows:反斜杠/ linux:正斜杠\
* 作用:用于替代路径中写死的分隔符,使程序更加灵活。
* 2.构造方法
* 概述:在创建File对象时,路径可以真实存在也可以不存在;路径可以是相对路径也可以是绝对路径;
* 路径可以是文件夹结尾也可以是文件结尾;并不影响File对象的创建
* 2.1 使用指定路径作为参数
* File file = new File(String pathName);
* 2.2 使用2个指定路径,拼接后作为文件路径
* File file = new File(String parent,String child);
* 2.3 使用一个file对象,和一个路径名
* File file = new File(file parent,String child);
* 3.其它方法
* 3.1 创建功能
* 3.1.1 创建文件对象
* boolean createNewFile();
* 3.1.2 创建单级文件夹对象
* boolean mkDir();
* 3.1.3 创建多级的文件夹对象
* boolean mkDirs();
* 3.2 删除功能
* 3.2.1 删除文件。
* delete();该方法会从磁盘上直接删除文件,不会进入回收站,只有在文件路径正确时,才会删除。
* 如果目标问价夹下还有子文件,不会删除。
* deleteOnExit():在jvm停止后,才删除文件。
* 3.3 获取信息(查询)功能
* 3.3.1 获取文件路径
* 3.3.2 获取父File的信息
* 3.3.3 获取文件名称
* 3.3.4 获取文件夹下的子文件名称
* 3.3.5 获取子文件File
* 3.4 判断功能
* 3.4.1 判断文件是否存在
* 3.4.2 是文件还是文件夹
* 3.4.3 判断文件是否可写、可读、隐藏。
* Date-Of-Create:2020/7/6-9:07
*/
public class FileDemo {
public static void main(String[] args) throws IOException {
//静态变量
/*sep();*/
//构造函数
/*cons();*/
//创建功能
/*mk();*/
//删除文件或者文件夹
/*delete();*/
//获取对象信息
/*getInfo();*/
//判断功能
check();
}
private static void check() {
String pathName = "C:\\Users\\aipande\\Desktop\\testDemo\\IO\\abc\\def";
File file = new File(pathName);
//判断是否存在
/*System.out.println(file.exists());
if(!file.exists()){
file.mkdirs();
}*/
//判断是文件还是文件夹,对于不是实际存在的文件,无法判断是文件还是文件夹,注意不能根据文件路径判断是文件还是文件夹
System.out.println(file.isDirectory());
}
private static void getInfo() throws IOException {
String pathName = "C:\\Users\\aipande\\Desktop\\testDemo\\IO\\abc\\def";
File file = new File(pathName);
//获取文件绝对路径
System.out.println(file.getAbsolutePath());
//获取构造时传入的路径
System.out.println(file.getPath());
//父路径
System.out.println(file.getParent());
//父File对象。在给定一个路径,创建文件的时候,可以先使用该方法获取父File对象,
//判断是否存在exsit(),如果不存在,再调用mkDirs()方法,避免父File文件夹不存在的问题
System.out.println(file.getParentFile());
//获取文件名称
System.out.println(file.getName());
//获取规范路径,没啥特别的用处,貌似和获取绝对路径的结果相同
System.out.println(file.getCanonicalPath());
//遍历文件夹,这里可以使用FileFilter过滤
File[] files = file.listFiles();
String[] fileName = file.list();
}
private static void delete() {
String pathName = "C:\\Users\\aipande\\Desktop\\testDemo\\IO\\abc\\def";
File file = new File(pathName);
System.out.println(file.delete());
}
private static void mk() throws IOException {
StringBuffer buffer = new StringBuffer();
String sep = File.separator;
buffer.append("C:").append(sep).append("Users").append(sep).append("aipande")
.append(sep).append("Desktop").append(sep).append("testDemo").append(sep).append("IO").append(sep)
.append("abc").append(sep).append("def");
System.out.println(buffer.toString());
File file = new File(buffer.toString());
//创建文件,文件之前的所有文件夹必须已存在,否则抛出IO异常:系统找不到指定路径。
//file.createNewFile();
//创建单级文件夹,只能创建最后一级文件夹,如果最后一级文件夹的前置文件夹不存在,那么不会创建文件夹
//file.mkdir();
//创建多级文件夹,如果最后一级文件夹的前置文件夹不存在,那么也会创建前置文件
file.mkdirs();
}
private static void cons() {
String path = "C:\\Users\\aipande\\Desktop\\testDemo\\IO";
File file = new File(path);
File file1 = new File(path,"abc.txt");
File file2 = new File(file,"def.txt");
System.out.println(file);
System.out.println(file1);
System.out.println(file2);
}
public static void sep(){
//获取系统路径分隔符
String pathSep = File.pathSeparator;
System.out.println(pathSep);
//获取名称分隔符
String sep = File.separator;
System.out.println(sep);
//用于替换路径中的分隔符
StringBuffer path = new StringBuffer();
path.append("C:").append(sep).append("new").append(sep);
System.out.println(path);
}
2.2 字节流
所有InputStream的子类都是输入字节流,所有OutputStream的子类都是字节输出流。
InputStream:抽象类,是所有字节输入流的超类。
//关闭流,释放资源
public void close();
//读取单个字节,读取下一个字节,返回该字节的int值(int类型有4个字节,将byte类型前的字节以0补齐的值,返回)
public int read();
//最多读取bytes.length个字节到数组中,返回值为读取的字节个数,如果没有可读字节,返回-1
public int read(byte[] bytes);
//最多读取len个字节,放到数组的指定位置,返回读取的字节个数
public int read(byte[] bytes,int offSet,int len);
//在流中做一个标记,该方法一般配合reset()方法使用
public void mark(int readlimit)
//将流重新定位到上一个标记的地方,可以实现重复读取字节
public void reset()
OutputStream:抽象类,是所有字节输出流的超类。
//关闭流,释放资源
public void close();
//写入一个字节,int类型由4个字节组成,这里只会取i低8位写入文件中。
public void write(int i);
//写入多个字节,将字节数组中的元素都写入文件中。
public void write(byte[] bytes);
//写入多个字节,从off位置开始,写入len个字节到文件中
public void write(byte[] bytes,int off,int len);
//刷新方法。如果输出流有缓冲区,调用该方法,会将缓冲区中的所有数据写入到文件中,注意,有缓冲区的输出流才有必要使用该方法
public void flush();
2.2.1 FileInputStream 和 FileOutputStream
FileInputStream:文件字节输入流,以字节为单位读取文件中的数据。
FileOutputStream:文件字节输出流,以字节为单位写入磁盘上的文件中。
FileInputStream:
1.构造方法
- 因为是读取文件,所以在创建对象时,需要指定源文件(从哪里读),可以使用字符串路径,也可以使用File对象。
-
1.1 FileInputStream fis = new FileInputStream(String pathName);
-
上面两种构造方法,实质是一样的:1.2 FileInputStream fis = new FileInputStream(File file);
//源码。判断路径是否为空,不为空则创建一个File对象,再调用FileInputStream(File file); public FileInputStream(String name) throws FileNotFoundException { this(name != null ? new File(name) : null); }
- 2.其它方法
- 概述:每个字节流再创建的时候,在字节流的头部都有一个指针,调用read方法时,会将指针后移,再次调用read方法会从指针的位置向后读取
-
2.1 public int read();读取下一个字节,返回该字节的int值(int类型有4个字节,将byte类型前的字节以0补齐的值,返回int值)
-
2.2 public int read(byte[] bytes);最多读取bytes.length个字节到数组中,返回值为读取的字节个数,如果没有可读字节,返回-1
-
2.3 public int read(byte[] bytes,int offSet,int len);最多读取len个字节,放到数组的指定位置,返回读取的字节个数
- 3.关闭流,释放资源的方法
-
close();流关闭以后,就不能再读取字节了。
FileOutputStream:
- 1.构造方法
- 因为是写入,所以需要知道目标文件的地址,即往哪里写的问题。注意:在创建FileOutputStream对象时,如果目标文件不存在,会先尝试去创建目标文件。但如果目标文件路径表示的是文件夹、或者是文件但是无法创建,会抛出IO异常。
- 1.1 FileOutputStream fos = new FileOutputStream(String pathName,boolean append);
-
pathName:指定文件的路径。
-
append:如果为true,表示在写入时,会将数据添加到原文件中。否则,则会覆盖原文件的内容。
- 1.2 FileOutputStream fos = new FileOutputStream(String pathName);
-
pathName:指定文件的路径。append默认为false。
- 1.3 FileOutputStream fos = new FileOutputStream(File file,boolean append);
-
与第一种构造方法本质是一样的,只是第一种方法执行了一个new File(pathName)的过程。
- 1.4 FileOutputStream fos = new FileOutputStream(File file);
-
与第二种方法本质一样。
- 2.其他方法
- 主要是继承自OutputStream的几种方法。参考OutputStream的内容。
小结:
1.flush方法和close方法的区别?
flush方法会将缓冲区中的数据写入文件,但不会关闭流。close方法也会将缓冲区中的内容写到文件中,但是会关闭流。流关闭后,无法再写入数据。
2.2.2 ObjectInputStream和ObjectOutputStream
首先介绍对象的序列化和反序列化:
序列化:将对象转换成字节序列的过程。
反序列化:将字节序列恢复成对象的过程。
ObjectInputStream:对象字节输入流。作用:对象的反序列化,即将字节序列读取到内存中,并恢复成对象。
ObjectOutputStream:对象字节输出流。对象的序列化,将对象以字节的形式保存或传输。
ObjectInputStream:
构造方法:
1.ObjectOutputStream oos = new ObjectOutputStream(OutputStream out);
特殊方法:
public Object readObject();从字节流中读取一个对象。
ObjectOutputStream:
1.ObjectOutputStream oos = new ObjectOutputStream(OutputStream out);
特殊方法:
public void writeObject(Object object);将对象写入文件。
小结:
1.类如果要实现序列化,必须实现Serializable接口。
2.可以使用transient关键字修饰变量,使该变量不会被序列化。(作用类似于static)
2.2.3 BufferedInputStream和BufferedOutputStream
BufferedInputStream:缓冲字节输入流。就是在字节输入流的基础上,加了一个缓冲区,以提高字节读取的效率。
BufferedOutputStream:缓冲字节输出流。同上。
对于缓冲输出流来说,如果想要立即看到写入效果,可以调用flush方法。
BufferedInputStream:
因为是对字节输入流添加缓冲功能,因此,需要一个字节输入流作为构造参数。
构造方法:
- 1.BufferedInputStream bis = new BufferedInputStream(InputStream inputStream);//使用默认大小的直接缓冲数组
- 2.BufferedInputStream bis = new BufferedInputStream(InputStream inputStream,int size);//指定缓冲字节数组的大小
BufferedOutputStream
构造方法:
- 1.BufferedOutputStream bos = new BufferedOutputStream(OutputStream os);
- 2.BufferedOutputStream bos = new BufferedOutputStream(OutputStream os,int size);
2.3 字符流
Reader:所有字符输入流的超类。
Writer:所有字符输出流的超类。