1. 什么是IO
- /O 即输入Input/ 输出Output的缩写,其实就是计算机调度把各个存储中(包括内存和外部存储)的数据写入写出的过程;
- java中用“流(stream)”来抽象表示这么一个写入写出的功能,封装成一个“类”,都放在http://java.io这个包里面。
2. 如何理解这个 '流'
通过“流”的形式允许java程序使用相同的方式来访问不同的输入/输出源。stream是从起源(source)到接收的(sink)的有序数据。我们这里把输入/输出源对比成“水桶”,那么流就是“管道”,这个“管道”的粗细、单向性等属性也就是区分了不同“流”的特性。
3. 认识文件
1.什么是文件
针对硬盘这种持久化存储的I/O设备,当我们想要进行数据保存时,往往不是保存成一个整体,而是独立成一个个的单位进行保存,这个独立的单位就被抽象成文件的概念,这就叫做文件
文件管理 采用的是树形结构,是N叉树,至于目录,其实就是文件夹
2. 文件路径
路径分为绝对路径和相对路径:
绝对路径:从树的根部开始查找
相对路径:从树的某一个节点为基准进行查找
文件分为文本文件和二进制文件:
文本文件就是放在记事本上能看懂的,比如.txt文件
二进制文件就是放在记事本上看不懂的,比如.docx,.jpg,.image等
4. 文件操作类
Java标准库为我们提供了 File 这个类;
File 对象是文件操作的一个抽象表示:文件是存储在硬盘上的,不太方便。直接在内存中创建一个对应的对象,操作到这个内存对象,就可以间接的影响到硬盘的文件情况了。
File 类的属性:
修饰符及类型 | 属性 | 说明 |
static String | pathSeparator | 依赖于系统的路径分隔符,String 类型的表示 |
static char | pathSeparator | 依赖于系统的路径分隔符,char 类型的表示 |
File 类的构造方法:
签名 | 说明 |
File(File parent, String child) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例 |
File(String pathname) | 根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者 相对路径 |
File(String parent, String child) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用 路径表示 |
File 类的方法:
它的方法有很多,不一一列举
值类型 | 方法签名 | 说明 |
String | getParent() | 返回 File 对象的父目录文件路径 |
String | getName() | 返回 FIle 对象的纯文件名称 |
String | getPath() | 返回 File 对象的文件路径 |
String | getAbsolutePath() | 返回 File 对象的绝对路径 |
String | getCanonicalPath() | 返回 File 对象的修饰过的绝对路径 |
boolean | exists() | 判断 File 对象描述的文件是否真实存在 |
boolean | isDirectory() | 判断 File 对象代表的文件是否是一个目录 |
boolean | isFile() | 判断 File 对象代表的文件是否是一个普通文件 |
boolean | createNewFile() | 根据 File 对象,自动创建一个空文件。成功创建后返 回 true |
boolean | delete() | 根据 File 对象,删除该文件。成功删除后返回 true |
void | deleteOnExit() | 根据 File 对象,标注文件将被删除,删除动作会到 JVM 运行结束时才会进行 |
还有其他的方法,我们要用到时,可以自己去查,而且我们看名字其实就可以知道这些方法的作用了。
具体的代码演示我在这里不过多演示。
文件内容操作:
计算机对文件操作有很多种操作,我们将其分为很多组类。
- 针对文本文件操作提供了一组类,统称为 " 字符流 "(典型代表:Reader、Writer)读写的基本单位是字符。
- 针对二进制文件操作提供了一组类,统称为 " 字节流 "(典型代表:InputStream、OutputStream) 读写的基本单位是字节。
流的原理解析:
流其实我们可以想象成一个“水管”,源端和目的端就是两个“水桶”,数据是通过这个“水管”进行流动传输的,以InputStream和Reader为例,水管的每个“水滴”就是具体的数据,如果是字节流,那么一个“水滴”就是一个字节,如果是字符流,那么一个“水滴”就是一个字符。
当创建一个流对象的时候,如fis=new FileInputStream(“…\xx\xx.txt”),记录指针来表示当前正准备从哪个“水滴”开始读取,每当程序从InputStream或者Reader里面取出一个或者多个“水滴”后,记录指针自定向后移动;除此之外,InputStream和Reader里面都提供了一些方法来控制记录指针的移动。
如果是处理流的话,就相当于在这个水管上面装了一些“控制阀门”,最终用户只要关心“阀门”具备的能力就行
按照流的流向来分,可以分为输入流和输出流。输入,输出都是从程序运行所在内存的角度来划分的。
- 输入流:只能从中读取数据,而不能向其写入数据,由InputStream和Reader作为基类。
- 输出流:只能向其写入数据,而不能从中读取数据。由OutputStream和Writer作为基类。
按照流的角色来分,可以分为节点流和处理流。
- 节点流:可以从向一个特定的IO设备(如磁盘、网络)读/写数据的流。也被称为低级流。
- 处理流:用于对一个已存在的流进行连接或封装,通过封装后的流来实现数据读/写功能。也称为高级流
java.io 这个包下有很多流,我们不需要一个个去看,很多时候知道原理,直接去查就可以了,我去抄一张人家大佬总结出来的图:
接下来介绍四种常见的流。
Java IO流四大家族:
四大家族的首领:
- java.io.InputStream 字节输入流
- java.io.OutputStream 字节输出流
- java.io.Reader 字符输入流
- java.io.Writer 字符输出流
四大家族的首领都是抽象类。(abstract class):
所有的流都实现了:
java.io.Closeable接口,都是可关闭的,都有close()方法:
有的输出流都实现了:
java.io.Flushable接口,都是可刷新的,都有flush()方法。刷新一下。这个刷新表示将通道/管道当中剩余未输出的数据。作用就是清空管道。没有flush()可能会导致丢失数据。
在java中只要“类名”以Stream结尾的都是字节流。以“Reader/Writer”结尾的都是字符流。
四大家族首领常用方法:
1.InputStream(字节输入流)
- void close() 关闭此输入流并释放与该流关联的所有系统资源。
- abstract int read() 从输入流读取下一个数据字节。
- int read(byte[] b) 从输入流中读取一定数量的字节并将其存储在缓冲 区数组 b 中。
- int read(byte[] b, int off, int len) 将输入流中最多 len 个数据字节读入字节数组。
2.OutputStream(字节输出流)
- void close() 关闭此输出流并释放与此流有关的所有系统资源。
- void flush() 刷新此输出流并强制写出所有缓冲的输出字节。
- void write(byte[] b) 将 b.length 个字节从指定的字节数组写入此输出 流。
- void write(byte[] b, int off, int len) 将指定字节数组中从偏移量 off 开始的 len 个字 节写入此输出流。
- abstract void write(int b)将指定的字节写入此输出流。
3.Reader(字符输入流)
- abstract void close() 关闭该流。
- int read() 读取单个字符。
- int read(char[] cbuf) 将字符读入数组。
- abstract int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分
4.Writer(字符输出流)
- Writer append(char c) 将指定字符追加到此 writer。
- abstract void close() 关闭此流,但要先刷新它。
- abstract void flush() 刷新此流。
- void write(char[] cbuf) 写入字符数组。
- abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。
- void write(int c) 写入单个字符
具体的代码这里就不演示了。