[Java学习笔记] IO
总结自廖雪峰大佬的教程
Java教程 - 廖雪峰的官方网站 (liaoxuefeng.com)https://www.liaoxuefeng.com/wiki/1252599548343744
目录
File
Java标准库的java.io.File对象表示一个文件或者目录:
创建File对象本身不涉及IO操作;
- 可以获取路径/绝对路径/规范路径:getPath()/getAbsolutePath()/getCanonicalPath();
- 可以获取目录的文件和子目录:list()/listFiles();
- 可以创建或删除文件和目录。
File对象既可以表示文件,也可以表示目录。特别要注意的是,构造一个File对象,即使传入的文件或目录不存在,代码也不会出错,因为构造一个File对象,并不会导致任何磁盘操作。只有当我们调用File对象的某些方法的时候,才真正进行磁盘操作。
例如,调用isFile(),判断该File对象是否是一个已存在的文件,调用isDirectory(),判断该File对象是否是一个已存在的目录:
用File对象获取到一个文件时,还可以进一步判断文件的权限和大小:
- boolean canRead():是否可读;
- boolean canWrite():是否可写;
- boolean canExecute():是否可执行;
- long length():文件字节大小。
对目录而言,是否可执行表示能否列出它包含的文件和子目录。
有些时候,程序需要读写一些临时文件,File对象提供了createTempFile()来创建一个临时文件,以及deleteOnExit()在JVM退出时自动删除该文件。
public class Main {
public static void main(String[] args) throws IOException {
File f = File.createTempFile("tmp-", ".txt"); // 提供临时文件的前缀和后缀
f.deleteOnExit(); // JVM退出时自动删除
System.out.println(f.isFile());
System.out.println(f.getAbsolutePath());
}
}
true
/tmp/tmp-17585469961555042196.txt
练习:打印所有文件和子文件夹的内容
import java.io.File;
import java.io.IOException;
public class demo {
public static void main(String[] args) throws IOException {
File currentDir = new File(".");
printAllFile(currentDir.getCanonicalFile());
}
static void printAllFile(File dir) {
// 打印所有文件和子文件夹的内容
File[] files = dir.listFiles();
if(files != null){
for(File f : files){
System.out.println(f.getName());
}
}
}
}
InputStream/OutputStream
Java标准库的java.io.InputStream/java.io.OutputStream
定义了所有输入/输出流的超类:
-
FileInputStream
实现了文件流输入,FileOutputStream
实现了文件流输出; -
ByteArrayInputStream
在内存中模拟一个字节流输入,ByteArrayOutputStream
在内存中模拟一个字节流输出。 -
某些情况下需要手动调用
OutputStream
的flush()
方法来强制输出缓冲区。 -
总是使用
try(resource)
来保证正确关闭。
InputStream
并不是一个接口,而是一个抽象类,它是所有输入流的超类。这个抽象类定义的一个最重要的方法就是int read()
,签名如下:
public abstract int read() throws IOException;
需要用try ... finally
来保证InputStream
在无论是否发生IO错误的时候都能够正确地关闭:
public void readFile() throws IOException {
InputStream input = null;
try {
// 定义1000个字节大小的缓冲区:
byte[] buffer = new byte[1000];
int n;
while ((n = input.read(buffer)) != -1) { // 读取到缓冲区
System.out.println("read " + n + " bytes.");
}
} finally {
if (input != null) { input.close(); }
}
}
用try ... finally
来编写上述代码会感觉比较复杂,更好的写法是利用Java 7引入的新的try(resource)
的语法,只需要编写try
语句,让编译器自动为我们关闭资源。推荐的写法如下:
public void readFile() throws IOException {
try (InputStream input = new FileInputStream("src/readme.txt")) {
// 定义1000个字节大小的缓冲区:
byte[] buffer = new byte[1000];
int n;
while ((n = input.read(buffer)) != -1) { // 读取到缓冲区
System.out.println("read " + n + " bytes.");
}
} // 编译器在此自动为我们写入finally并调用close()
}
实际上,编译器并不会特别地为InputStream
加上自动关闭。编译器只看try(resource = ...)
中的对象是否实现了java.lang.AutoCloseable
接口,如果实现了,就自动加上finally
语句并调用close()
方法。InputStream
和OutputStream
都实现了这个接口,因此,都可以用在try(resource)
中
在调用InputStream
的read()
方法读取数据时,read()
方法是阻塞的
int n;
n = input.read(); // 必须等待read()方法返回才能执行下一行代码
int m = n;
Filter模式(少量的类实现功能组合)
当我们需要给一个“基础”InputStream
附加各种功能时,我们先确定这个能提供数据源的InputStream
,因为我们需要的数据总得来自某个地方,例如,FileInputStream
,数据来源自文件:
InputStream file = new FileInputStream("test.gz");
紧接着,我们希望FileInputStream
能提供缓冲的功能来提高读取的效率,因此我们用BufferedInputStream
包装这个InputStream
,得到的包装类型是BufferedInputStream
,但它仍然被视为一个InputStream
:
InputStream buffered = new BufferedInputStream(file);
最后,假设该文件已经用gzip压缩了,我们希望直接读取解压缩的内容,就可以再包装一个GZIPInputStream
:
InputStream gzip = new GZIPInputStream(buffered);
无论我们包装多少次,得到的对象始终是InputStream
,我们直接用InputStream
来引用它,就可以正常读取:
┌─────────────────────────┐
│GZIPInputStream │
│┌───────────────────────┐│
││BufferedFileInputStream││
││┌─────────────────────┐││
│││ FileInputStream │││
││└─────────────────────┘││
│└───────────────────────┘│
└─────────────────────────┘
上述这种通过一个“基础”组件再叠加各种“附加”功能组件的模式,称之为Filter模式(或者装饰器模式:Decorator)。它可以让我们通过少量的类来实现各种功能的组合:
┌─────────────┐
│ InputStream │
└─────────────┘
▲ ▲
┌────────────────────┐ │ │ ┌─────────────────┐
│ FileInputStream │─┤ └─│FilterInputStream│
└────────────────────┘ │ └─────────────────┘
┌────────────────────┐ │ ▲ ┌───────────────────┐
│ByteArrayInputStream│─┤ ├─│BufferedInputStream│
└────────────────────┘ │ │ └───────────────────┘
┌────────────────────┐ │ │ ┌───────────────────┐
│ ServletInputStream │─┘ ├─│ DataInputStream │
└────────────────────┘ │ └───────────────────┘
│ ┌───────────────────┐
└─│CheckedInputStream │
└───────────────────┘
本文来自博客园,作者:泥烟,CSDN同名, 转载请注明原文链接:https://www.cnblogs.com/Knight02/p/15799041.html