IO 流
概述
-
IO:输入/输出(Input/Output)
-
流:是一种抽象概念,是对数据传输的总称,也就是说数据在设备间的传输称为流,流的本质是数据传输
-
IO 流就是用来处理设备间数据传输问题的
- 常见的应用:文件复制、文件上传、文件下载
-
IO 流分类:
- 按照数据的流向
- 输入流:读数据
- 输出流:写数据
- 按照数据类型
- 字节流:字节输入流、字节输出流
- 字符流:字符输入流、字符输出流
- 按照数据的流向
-
字节流:
-
字符流:
File
概述
- File:它是文件和目录路径名的抽象表示
- 文件和目录是可以通过 File 封装成对象的
- 对于 File 而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已,该路径可以是存在的,也可以是不存在的。
File 类的构造方法
方法名 | 说明 |
---|---|
File(String pathname) | 通过将给定的路径名字字符串转换为抽象路径名来创建新的 File 实例 |
File(String parent,String child) | 从父路径名字符串和子路径名字符串创建新的 File 实例 |
File(File parent,String child) | 从父抽象路径名和子路径名字符串创建新的 File 实例 |
- 注意:路径的分隔符 ’\‘ 需通过添加转义字符 ’\‘ 表示,格式为 ’\\‘。
File 类创建功能
方法名 | 说明 |
---|---|
public booleancreateNewFile() | 当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件 |
public booleanmkdir() | 创建由此抽象路径名命名的目录(创建单个目录) |
public booleanmkdirs() | 创建由此抽象路径名命名的目录,包括任何必须但不存在的父目录(创建多个嵌套目录) |
- 注意:系统要求目录与文件不能重名。
File 类删除功能
方法名 | 说明 |
---|---|
public booleandelete() | 删除由此抽象路径名表示的文件或目录 |
- 注意:
- 若为抽象路径名指定的是路径字符串是相对路径,则默认目录是 idea 的当前项目目录。
- 如果一个目录中有内容(目录,文件),不能直接删除。(只能删除空目录)
File 类判断和获取功能
方法名 | 说明 |
---|---|
public booleanisDirectory() | 测试此抽象路径名表示的 File 是否为目录 |
public booleanisFile() | 测试此抽象路径名表示的 File 是否为文件 |
public booleanexists() | 测试此抽象路径名表示的 File 是否存在 |
public StringgetAbsolutePath() | 返回此抽象路径名的绝对路径名字字符串 |
public StringgetPath() | 将此抽象路径名转换为路径名字字符串 |
public StringgetName() | 返回由此抽象路径名表示的文件或目录的名称 |
public String[]list() | 返回此抽象路径名表示的目录中的文件和目录的名称字符串数组 |
public File[]listFiles() | 返回此抽象路径名表示的目录中的文件和目录的 File 对象数组 |
递归
- 概述:以编程的角度来看,递归指的是方法定义中调用方法本身的现象
- 递归解决问题的思路:
- 把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解
- 递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算
- 递归解决问题需要找到两个内容:
- 递归出口:否则会出现内存溢出
- 递归规则:与原问题相似的规模较小的问题
字节流
字节流抽象基类
- InputStream:这个抽象类是表示字节输入流的所有类的超类
- OutputStream:这个抽象类是表示字节输出流的所有类的超类
- 子类名特点:子类名称都是以其父类名作为子类名的后缀
FileOutputStream 字节流写数据
-
FileOutputStream:文件输出流用于将数据写入 File
-
常用的构造方法:
方法名 说明 FileOutPutStream(String name) 创建文件输出流以指定的名称写入文件 FileOutPutStream(String name,boolean append) 当 append 参数为 true 时,写文件方式为追加写入 FileOutPutStream(File file) 创建文件输出流以指定的 File 对象写入文件 FileOutPutStream(File file,boolean append) 当 append 参数为 true 时,写文件方式为追加写入 -
常用的成员方法:
方法名 说明 voidwrite(int b) 将指定的字节写入此文件输出流,参数为 ASCII 码 voidwrite(byte[] b) 将 b.length 字节从指定的字节数组写入此文件输出流,一次写一个字节数组的数据 voidwrite(byte[] b,int off,int len) 将 len 字节从指定的字节数组开始,从偏移量 off 开始写入此文件输出流,一次写一个字节数组的部分数据 voidclose() 关闭此文件输出流并释放与此流相关联的任何系统资源 -
使用字节输出流写数据的步骤:
- 创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
- 调用字节输出流对象的写数据方法
- 关闭文件,并释放资源
-
String 中提供
getBytes()
方法可以将字符串转化为字节数组,方便数据的转化(Java 中默认一个汉字用 3 个字节存储(UTF-8)) -
当需要在文件中实现换行时,可以加上换行符(Idea 中的文件阅读器可以自动识别各种换行符)
- Windows:\r\n
- Linux:\n
- Mac:\r
字节流写数据的异常处理
-
finally:在异常处理时提供 finally 块来执行所有清除操作,比如 IO 流的释放资源
-
特点:被 finally 控制的语句一定会执行,除非 JVM 退出
-
常用的对 FileNotFoundException 和 IOException 异常的处理方法:
FileOutputStream fos = null; try { fos = new FileOutputStream("Z:\\myOutputStream\\fos2.txt"); fos.write("hello".getBytes()); } catch (IOException e) { // 捕获创建对象文件找不到及调用write方法时可能产生的异常 e.printStackTrace(); } finally { if (fos != null) { // 判断文件流对象是否创建成功(null),以免出现空指针报错 try { fos.close(); } catch (IOException e) { // 捕获调用close方法时可能产生的异常 e.printStackTrace(); } } }
- 注意:FileNotFoundException 属于 IOException 的子类,捕获异常时只需要捕获 IOException 即可。
-
JDK7 的改进方案:
try(定义流对象1;定义流对象2...){ 可能出现异常的代码; } catch(异常类名 变量名){ 异常的处理代码; } //自动释放资源,无需close
FileInputStream 字节流读数据
-
FileInputStream:从文件系统中的文件获取输入字节
-
常用的构造方法:
方法名 说明 FileInputStream(String name) 通过打开与实际文件的连接来创建一个 FileInputStream,该文件由文件系统中的路径名 name 命名 -
常用的成员方法:
方法名 说明 intread() 从该输入流读取一个字节的数据,返回值是字节数,若读不到数据,则返回 -1 intread(byte[] b) 从该输入流读取最多 b.length
个字节的数据到一个字节数组,返回值是实际读取的字节个数,若读不到数据,则返回 -1intread(byte[] b,int off,int len) 从该输入流读取最多 len
个字节的数据到字节数组voidclose() 关闭此文件输入流并释放与流相关联的任何系统资源 - String 中有构造方法 String(byte[] b,int offset,int length) ,可使用匿名内部类的方法将字节数组转化为字符串输出
字节缓冲流
-
BufferedOutputStream:该类实现缓冲输出流。通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
-
BufferedInputStream:创建 BufferedInputStream 将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
-
构造方法:
- 字节缓冲输出流:
BufferedOutputStream(OutputStream out)
- 字节缓冲输入流:
BufferedInputStream(InputStream in)
- 字节缓冲输出流:
-
字节缓冲流对象可以通过调用
write
和read
方法操作文件
字符流
为什么会出现字符流
- 由于字节流操作中文不是很方便,所以 Java 提供字符流
- 字符流 = 字节流 + 编码表
- 用字节流复制文本文件时,文本文件中也有中文,但是没有出现乱码问题,原因是最终底层操作会自动进行字节拼接成中文,底层是如何识别中文的呢?
- 汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数
- 不同编码存储一个汉字的字节数
- UTF-8:3 个字节
- GBK:2 个字节
字符串的编码和解码
- 编码:
byte[] getBytes()
:使用平台的默认字符集(Idea 中默认 UTF-8)将该 String编码为一系列字节,将结果存储到新的字节数组中byte[] getBytes(String charsetName)
:使用指定的字符集将该 String 编码为一系列字节,将结果存储到新的字节数组中
- 解码:
String(byte[] bytes)
:通过使用平台的默认字符集(Idea 中默认 UTF-8)解码指定的字节数组来构造新的 StringString(byte[] bytes,String charsetName)
:通过指定的字符集解码指定的字节数组来构造新的 String
字符流抽象基类
- Reader:字符输入流的抽象类
- Writer:字符输出流的抽象类
InputStreamReader 字符流读数据
-
常用的构造方法:
方法名 说明 InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader 对象 InputStreamReader(InputStream in, String charsetName) 创建一个使用指定字符集的 InputStreamReader -
常用的成员方法
方法名 说明 intread() 一次读一个字符数据,返回值是每个字符对应的 UTF-8 码,若读不到数据,则返回 -1 intread(char[] cbuf) 一次读一个字符数组数据,返回值是实际读取的字符个数,若读不到数据,则返回 -1
OutputStreamWriter 字符流写数据
-
字符流写数据时,写入的数据会暂时存储在缓冲区中,只要当刷新的时候,缓冲区中的数据才会被写入文件中(外存)
-
常用的构造方法:
方法名 说明 OutputStreamReader(InputStream in) 创建一个使用默认字符集的 OutputStreamReader 对象 OutputStreamReader(InputStream in, String charsetName) 创建一个使用指定字符集的 OutputStreamReader -
常用的成员方法:
方法名 说明 voidwrite(int c) 写一个字符 voidwrite(char[] cbuf) 写入一个字符数组 voidwrite(char[] cbuf,int off,int len) 写入字符数组的一部分 voidwrite(String str) 写一个字符串 voidwrite(String str,int off,int len) 写一个字符串的一部分 voidflush() 刷新流,还可以继续写数据 voidclose() 关闭流,释放资源,但是在关闭之前会先刷新流,一旦关闭,就不能再写数据
读写字符流便捷类
- 转换流的名字比较长,而常见的操作都是按照本地默认编码实现的,所以为了简化书写,转换流提供了对应的子类
- FileReader:用于读取字符文件的便捷类
FileReader(String fileName)
- FileWriter:用于写入字符文件的便捷类
FileWriter(String fileName)
- 注意:便捷类不提供指定编码读写的功能,若需要进行指定编码读写,还是要使用 InputStreamReader 和 OutputStreamWriter
字符缓冲流
- BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小,默认值足够大,可用于大多数用途。
BufferedWriter(Writer out)
- BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以接受默认大小,默认值足够大,可用于大多数用途。
BufferedReader(Reader in)
字符缓冲流特有功能
- BufferedWriter:
void newLine()
:写一行行分隔符(换行符),行分隔符字符串由系统属性定义
- BufferedReader:
public String readLine()
:读一行文字。结果包括行的内容的字符串,不包括任何终止字符,如果流的结尾已到达,则为 null
特殊操作流
标准输入输出流
-
System 类中有两个静态的成员变量
变量名 说明 public static finalInputStream in 标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源 public static finalPrintStream out 标准输出流。通常该流对应于显示输出或由主机环境或用户指定的另一个输出目标 -
通常使用以下方法实现键盘录入数据:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // in为InputStream类的对象
-
为解决以上书写麻烦等问题,Java 提供了一个类实现键盘录入:
Scanner sc = new Scanner(System.in);
-
标准输出流的使用:
PrintStream ps = System.out; ps.println(); // print()和println()方法广泛应用于在控制台输出内容
打印流
-
分类:
- 字节打印流:PrintStream
- 字符打印流:PrintWriter
-
特点:
- 只负责输出数据,不负责读取数据
- 有特有的方法(例如 print、println 等)
-
字节打印流
PrintSteam(String fileName)
:使用指定的文件名创建新的打印流
-
字符打印流
-
构造方法:
方法名 说明 PrintWriter(String fileName) 使用指定的文件名创建一个新的 PrintWriter,而不需要自动执行刷新 PrintWriter(Writer out,boolean autoFlush) 创建一个新的 PrintWriter(out:字符输出流;autoFLush:一个布尔值,若为真,则 println,printf 或 format 方法将刷新输出缓冲区
-
对象序列化流
-
对象序列化:指的是将对象保存到磁盘中,或者在网络中传输对象
这种机制就是使用一个字节序列不是一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息
字节序列写到文件之后,相当于文件中持久保存了一个对象的信息
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化
-
对象序列化流:ObjectOutputStream
-
对象反序列化流:ObjectInputStream
-
构造方法:
ObjectOutputStream(OutputStream out)
:产一个写入指定的 OutputStream 的 ObjectOutputStream -
序列化对象的方法:
void writeObject(Object obj)
:将指定的对象写入 ObjectOutputStream -
注意:
- 一个对象想要被序列化,该对象所属的类必须实现 Serializable 接口
- Serializable 是一个标记接口,实现该接口,不需要重写任何方法
对象反序列化流
-
构造方法:
ObjectInputStream(InputStream in)
:创建从指定的 InputStream 读取的 ObjectInputStream -
反序列化对象的方法:
Object readObject()
:从 ObjectInputStream 读取一个对象
serialVersionUID 和 transient
-
一个可序列化的类在加载后会默认计算出序列化 ID(serialVersionUID)的值,若使用对象序列化流序列化了一个对象后,修改了对象所属的类文件,读取数据会出现问题,并抛出 InvalidClassException 异常
-
为解决 InvalidClassException 异常的问题,可以给对象所属的类指定一个 serialVersionUID
private static final long serialVersionUID = 42L;
-
若一个对象中的某个成员变量的值不想被序列化,可以给该成员变量加上 transient 关键字修饰,该关键字标记的成员变量不参与序列化过程
Properties
-
概述
- 是一个 Map 体系的集合类
- Properties 可以保存到流中或从流中加载
-
Properties 作为集合的特有方法:
方法名 说明 ObjectsetProperty(String key,String value) 设置集合的键和值,都是 String 类型,底层调用 Hashtable 方法 put StringgetProperty(String key) 使用此属性列表中指定的键搜索属性 Set<String> stringPropertyNames() 从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串 -
Properties 和 IO 流结合的方法
方法名 说明 voidload(InputStream inStream) 从输入字节流读取属性列表(键和元素对) voidload(Reader reader) 从输入字符流读取属性列表(键和元素对) voidstore(OutputStream out,String comments) 将此属性列表(键和元素对)写入此 Properties 表中,以适合于使用 load(InputStream)
方法的格式写入输出字节流voidstore(Writer writer,String comments) 将此属性列表(键和元素对)写入此 Properties 表中,以适合于使用 load(Reader)
方法的格式写入输出字符流
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于