总结自廖雪峰大佬的教程

​Java教程 - 廖雪峰的官方网站 (liaoxuefeng.com)[Java学习笔记] IO_临时文件https://www.liaoxuefeng.com/wiki/1252599548343744​

目录

​File​

​练习:打印所有文件和子文件夹的内容​

​InputStream/OutputStream​

​Filter模式(少量的类实现功能组合)​



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());
}
}
}
}

[Java学习笔记] IO_编译器_02

 

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 │
└───────────────────┘