【JAVA进化论】LV4-1:java的IO-API

一、I/O家族

下图为java自带的IO操作的整体家族树状图,整体分为字节流和字符流两大类,它们的区别在于:

  1. 字节流是以字节为单位来传输数据,它按照输入/输出方向不同分为了两个大父类:InputStream和OutputStream
  2. 字符流是以多个字节为单位来传输数据,它按照输入/输出方向不同分为了两个大父类:Reader和Writer

⚠️ 注:本文仅讲字节流常用的几种读写数据的方式以及好用的nio api,其余想要详细了解可以网上查阅具体的资料。

图1

二、如何利用字节流读写数据?

2.1:写

我们现在写一个程序,让它新建一个文件,命名为a.txt,如果文件已经存在,则不再创建,然后通过程序往它的里面写入一句话:”Java是世界上坠吼滴语言!“:

代码块1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void main(String[] args) throws IOException {
File aFile; //声明文件类型变量
OutputStream os = null; //声明输出流类型变量
try {
aFile = new File("/Users/sunqinwen/Documents/a.txt");
if (!aFile.exists()) { //若文件不存在
if (!aFile.createNewFile()) { //利用createNewFile创建文件
System.out.println("创建文件失败!");
return;
}
}
os = new FileOutputStream(aFile); //和目标文件建立起数据流管道
os.write("Java是世界上坠吼滴语言!".getBytes(StandardCharsets.UTF_8)); //使用UTF-8的编码方式,写入到a文件
System.out.println("执行完毕!");
} finally {
if (os != null) {
os.close(); //管道用好了别忘了关闭
}
}
}

2.2:读

上方运行结果就是a文件被创建了出来,并且顺利将那段文本写了进去,现在我们再来写一个程序,把这个文件里的信息读入到程序中,这时就要借助我们的输入流InputStream了:

代码块2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static void main(String[] args) throws IOException {
File aFile; //声明文件类型变量
InputStream is = null; //声明输出流类型变量
try {
aFile = new File("/Users/sunqinwen/Documents/a.txt");
if (!aFile.exists()) { //若文件不存在
System.out.println("文件不存在!");
return;
}
is = new FileInputStream(aFile); //和目标文件建立起数据流管道
byte[] msg = new byte[1024]; //以1KB为单位,将文件里的数据读进来
StringBuilder sb = new StringBuilder();
int n;
while ((n = is.read(msg)) > 0) { //当read返回-1,说明文件里的内容已被读完,那么循环终止,否则返回的就是本次读进来的字节数
//一旦进入这里,msg里的字节信息就已经被更新了,而且是按照1KB的大小读入的
sb.append(new String(msg, 0, n, StandardCharsets.UTF_8)); //每次把读进来的字节累加到结果字符串里
}
System.out.println(sb); //直接把结果输出
} catch (IOException e) { //IO操作需要捕获处理IO异常
e.printStackTrace();
} finally {
if (is != null) {
is.close(); //管道用好了别忘了关闭
}
}
}

通过上面的方式,利用FileInputStream,可以将文件里的信息读出来。

对于文件读写、创建,理论上掌握一种方式就可以,但是你会发现上面的写法真的很啰嗦,java有没有更好的读写文件的方法呢?来看下一节。

三、利用JAVA NIO API创建&读写文件

不知道你发现了没,Mac系统的文件路径是正斜杠划分,而Windows系统却是反斜杠,这就意味着你上面的代码对于文件路径这一块在双系统下是不兼容的,而且上面的代码很繁琐,于是Java提供了更好用的NIO API,让我们来改造下上面的代码。

3.1:写

将”Java是世界上坠吼滴语言!“写入同路径的b.txt文件:

代码块3
1
2
3
4
5
6
7
8
public static void main(String[] args) throws IOException {
Path path = Paths.get("/Users", "sunqinwen", "Documents", "b.txt");
if (!Files.exists(path)) { //若文件不存在
Files.createFile(path); //创建文件
}
Files.write(path, "Java是世界上坠吼滴语言!".getBytes(StandardCharsets.UTF_8));
System.out.println("执行完毕!");
}

这里用Path来组装路径,利用Path组装后的路径会智能转成符合当前操作系统的路径模式。然后利用Files完成文件的创建和写入。

3.2:读

现在将这句话从文件里读出来,相比2.2,真的简化了好多:

代码块4
1
2
3
4
public static void main(String[] args) throws IOException {
Path path = Paths.get("/Users", "sunqinwen", "Documents", "b.txt");
System.out.println(Files.readString(path, StandardCharsets.UTF_8));
}

同样利用Path组装路径,然后利用Files读取数据。

Files读取数据时,我们可以详细探索下,它是很有用的一个工具类:

图2