Java IO 流
File
File是java.io包下的类,File类的对象,用于代表定期操作系统的文件夹(或文件夹)
注意:File类只能对文件夹本身进行操作,不能读写文件里存储的数据。
路径分隔符
路径分隔符可以用“File.separatar”来替代路径中的分隔符,而且"File.separatar"还可以兼容各种操作系统。v
工作空间
代码运行是在工作空间中运行的,想要找到对应文件需要确认好运行的工作空间路径。
public class MyTest {
public static void main(String[] args) throws Exception {
String currentProjectPath = System.getProperty("user.dir");
// 工作空间
// 我这边测试时输出的是: /Users/xxxx/IdeaProjects/MyTest
// 我实际java文件是存放在: /Users/xxxx/IdeaProjects/MyTest/src/MyTest.java
// 导致我想获取相对路径下的文件时总是找不到文件。
// 想获取的文件路径:/Users/xxxx/IdeaProjects/MyTest/src/File.txt
System.out.println("currentProjectPath ----" + currentProjectPath);
// 所以获取File文件,需要前面追加一个src
File file = new File("src/File.txt");
System.out.println("File Test ----" + file.getAbsolutePath());
System.out.println("File Test ----" + file.exists());
}
}
字符集
ASCII字符集
ASCII(American Standard Code for information Interchange):美国信息交换标准代码,包括了英文、符合等。
标准ASCII使用1个字节存储一个字符,首位时0,总共可表示128个字符。
为什么首位都是0,因为在计算机中数据存储都是以一个字节存储的,一个字节有8位,而128个字符只需要7位就能表示,为了能符合计算机的存储规范,首位追加一位0。
GBK字符集
汉字内码扩展规范。
汉字编码字符集,包含了2万多个汉字等字符。GBK中中文字符编码成两个字节的形式存储。
注意:GBK兼容了ASCII字符集。(因为日常使用中我们也需要使用英文/符合/数字)
GBK规定,汉字的第一个字节的第一位必须是1。(这样是为了在编解码的时候能够区分ASCII字符集和GBK字符集。)
Unicode字符集(统一码,也叫万国码)
UTF-32
UTF-8
UTF-8编码方式
对于ASCII码,字符前必须要以0开头。
对于中文,用三个字节表示,第一个字节需要以“1110”开头,第二和第三个字节需要以“10”开头。
IO流
文件流
IO流总体来看就有四大流
- 字节输入流
- 字节输出流
- 字符输入流
- 字符输出流
FileInputStream(文件字节输入流)
构造方法 / read
构造方法
- File对象为参数调用构造方法,new FileInputStream(new File(filePath))
- 文件路径为参数调用构造方法,new FileInputStream(filePath)
read()
- 每次调用返回一个字节,如果没有数据,返回 -1
使用循环读取文件数据
read(byte[] buffer)
- 每次调用读取多个字节,读取不到字节时返回 -1
read(buffer)每次读取字节时不会清除原有数据,所以在读取时需要注意“读取多少,倒出多少”。
循环调用的方式读取文件。(日常使用最多的使用方式,如:拷贝文件)
一次性读取完文件全部字节 readAllBytes()
Q:为什么要一次性读取完文件字节?
A:因为读取文件会频繁调用系统能力,系统能力是非常消耗资源的,所以在读取文件的时候都应该尽量减少调用系统能力。
一次性读取文件全部的文字虽然说可以降低系统能力调用,但是会导致占据大量的内存空间
是否使用该方法,需要结合自身业务情况决定。
FileOutputStream(文件字节输出流)
构造方法 / write
FileOutputStream的构造函数,如果文件不存在会创建文件。
- write(int a)方法,一次只能写出一个字节,所以在写出中文的时候需要注意中文是3个字节(UTF-8)组成的。
- 写出换行符需要将换行字符“\r\n”转换成字节数组。
实例:文件复制
- 关闭流的时候应该遵循,后开启的流先关闭,先开启的流后关闭。
- 系统中所有文件都是由字节组成的,所以上面的这个程序是可以复制所用类型的文件的。
释放资源
为了避免程序在运行的中途发生异常导致开启的流无法关闭,调用流操作时需要用try-catch,并且在finally中关闭流。
因为在finally中释放资源代码太臃肿了,所以JDK 7后提供了更简洁的方式try-with-resource
try(资源对象),只能放置资源对象。
Q: 如果知道哪些对象是资源对象?
A: 资源都是会实现AutoCloseable接口,资源都会有一个close方法。
其实只要实现了AutoCloseable接口(我们自定义的类),都可以通过try-with-resource来调用close方法
FileReader(文件字符输入流)
构造方法 / read
在读取文件内容的时候,字符输入流相对字节输入流。因为一次读取的字节数比字节流多,所以性能相对较好。
FileWriter (文件字符输出流)
构造方法 / write
- 文件字符输出流,在写数据的时候并不是实时将数据写到文件中,而是会将数据存放在缓存区。这些字符会在调用flush()刷先流或close()关闭流的时候,才会将数据写出到文件中。
- 当缓存区数据被占满的时候,会在下次调用写入时先将缓存区数据刷新写出到文件中。
缓冲流
通过开辟一个缓冲池,降低系统调用频次,提供性能。
可以根据实际需求定义缓冲池大小。
字节缓冲输入流
每次输入按照8KB字节大小进行输入,减少调用系统的次数,提供读写性能。
字符缓冲输入流
同理字节缓冲输入流,字符是用字符缓冲池,字节是用字节缓冲池 。
读取的时候,读取的行没有内容会返回Null
字符缓冲输出流
转换流
用于解决不同编码时,字符流读取文本内容乱码的问题。
字符输入转换流
将字符流转换成字节流进行读取,然后根据编码规则转成字符流输入。
字符输出转换流
流与流之间能进行包装。
打印流
打印输出流
想打什么就打什么,不需要进行数据类型的转换。
打印字节流
打印字符流
各种IO流之间都是通过包装的方式实现功能叠加的,高级流想要低级流的功能只能在构建的时候传入低级流。
System.out.println()使用的就是打印流,我们可以通过setOut()函数,修改打印流的输出文件。
数据流
在某些场景,希望能将数据以自身数据类型写出,并且能读取回来。
数据输出流
数据输入流
读的顺序必须要与,写的顺序保持一致。
序列化流
对象序列化必须要实现Serializable接口。
如果有参数不想参与序列化,可以通过transient标记。
对象字节输出流
对象字节输入流