一、File类
1. File
File
(文件)类这个名字有一定的误导性,我们可能认为它指代的是文件,实际上却并非如此,它技能代表一个特定文件的名称,又能代表一个目录下的一组文件的名称,如果它指定的是一个文件集,我们就可以对此集合调用list()
方法,这个方法会返回一个字符数组。
class DirFilter implements FilenameFilter {
private Pattern pattern;
public DirFilter(String regex) {
pattern = Pattern.compile(regex);
}
@Override
public boolean accept(File dir, String name) {
return pattern.matcher(name).matches();
}
}
/**
* @Author ZhangGJ
* @Date 2020/12/04 07:51
*/
public class DirList {
public static void main(String[] args) {
/**
* "."代表的路径:当前目录,项目所处的目录
*/
File path = new File(".");
String[] list;
if (args.length == 0) {
list = path.list();
} else {
list = path.list(new DirFilter(args[0]));
}
Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
for (String dirItem : list) {
System.out.println(dirItem);
}
}
}
匿名内部类版本:
/**
* @Author ZhangGJ
* @Date 2020/12/04 07:53
*/
public class DirList2 {
public static FilenameFilter filter(final String regex) {
return new FilenameFilter() {
private Pattern pattern = Pattern.compile(regex);
@Override
public boolean accept(File dir, String name) {
return pattern.matcher(name).matches();
}
};
}
public static void main(String[] args) {
File path = new File(".");
String[] list;
if (args.length == 0) {
list = path.list();
} else {
list = path.list(filter(args[0]));
}
Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
for (String dirItem : list) {
System.out.println(dirItem);
}
}
}
更进一步:
/**
* @Author ZhangGJ
* @Date 2020/12/04 07:53
*/
public class DirList3 {
public static void main(final String[] args) {
File path = new File(".");
String[] list;
if (args.length == 0) {
list = path.list();
} else {
list = path.list(new FilenameFilter() {
private Pattern pattern = Pattern.compile(args[0]);
@Override
public boolean accept(File dir, String name) {
return pattern.matcher(name).matches();
}
});
}
Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
for (String dirItem : list) {
System.out.println(dirItem);
}
}
}
2.目录实用工具
/**
* @Author ZhangGJ
* @Date 2020/12/04 08:13
*/
public final class Directory {
public static File[] local(File dir, final String regex) {
return dir.listFiles(new FilenameFilter() {
private Pattern pattern = Pattern.compile(regex);
@Override
public boolean accept(File dir, String name) {
return pattern.matcher(new File(name).getName()).matches();
}
});
}
public static File[] local(String path, final String regex) { // Overloaded
return local(new File(path), regex);
}
// A two-tuple for returning a pair of objects:
public static class TreeInfo implements Iterable<File> {
public List<File> files = new ArrayList<File>();
public List<File> dirs = new ArrayList<File>();
// The default iterable element is the file list:
@Override
public Iterator<File> iterator() {
return files.iterator();
}
void addAll(TreeInfo other) {
files.addAll(other.files);
dirs.addAll(other.dirs);
}
@Override
public String toString() {
return "dirs: " + PPrint.pformat(dirs) + "\n\nfiles: " + PPrint.pformat(files);
}
}
public static TreeInfo walk(String start, String regex) { // Begin recursion
return recurseDirs(new File(start), regex);
}
public static TreeInfo walk(File start, String regex) { // Overloaded
return recurseDirs(start, regex);
}
public static TreeInfo walk(File start) { // Everything
return recurseDirs(start, ".*");
}
public static TreeInfo walk(String start) {
return recurseDirs(new File(start), ".*");
}
static TreeInfo recurseDirs(File startDir, String regex) {
TreeInfo result = new TreeInfo();
for (File item : startDir.listFiles()) {
if (item.isDirectory()) {
result.dirs.add(item);
result.addAll(recurseDirs(item, regex));
} else if (item.getName().matches(regex)) {
result.files.add(item);
}
}
return result;
}
public static void main(String[] args) {
if (args.length == 0) {
System.out.println(walk("."));
} else {
for (String arg : args) {
System.out.println(walk(arg));
}
}
}
}
3.目录的检查以及创建
File类不仅仅只代表存在的文件或目录,也可以用File对象来创建新的目录或者不存在的整个目录路径,我们还可以查看文件的特性(如:大小,最后修改日期,读/写),检查某个File对象代表的是一个文件还是一个目录,并且可以删除文件。
二、输入和输出
编程语言中的I/O
类库中常使用流这个抽象概念,它代表任何有能力产出数据的数据源对象或者是有能力接受数据的接收端对象,流
屏蔽了实际的I/O
设备中处理数据的细节。
Java类库中I/O
类分成输入和输出两部分,任何自InputStream
或Reader
派生而来的类都含有名为read()
的基本方法,用于读取单个字节或者字节数组,同样,任何自OutputStream
或Writer
派生而来的类都含有名为write()
的基本方法,用于写单个字节或者字节数组。但是,我们通常不会用到这些方法,它们之所以存在是因为别的类可以使用它们,以便提供更有用的接口,因此,我们很少使用单一的类来创建流对象,而是通过叠合多个对象来提供所期望的功能。实际上,Java中的流类库让人迷惑饿主要原因就在于:创建单一的结果流,却需要创建多个对象。
与输入有关的所有类都应该从InputStream
继承,与输出相关的类都应该从OutputStream
继承。
1.InputStream
InputStream
的作用是用来表示那些从不同数据源产生输入的类。
类 | 功能 | 构造器 | 如何使用 |
---|---|---|---|
ByteArrayInputStream | 允许将内存的缓冲区当作InputStream 使用 | 缓冲区,字节将从中取出 | 作为一种数据源:将其与FilterInputStream 对象相连以提供有用接口 |
StringBufferInputStream | 将String 转换成InputStream 。 | 字符串,底层实现实际使用StringBuffer | 作为一种数据源:将其与FilterInputStream 对象相连以提供有用接口 |
FileInputStream | 用于从文件中读取信息 | 字符串,表示文件名、文件或FileDescriptor 对象 | 作为一种数据源:将其与FilterInputStream 对象相连以提供有用接口 |
PipedInputStream | 产生用于写入相关PipedOutputStream 的数据源,实现“管道化”概念 | PipedOutputStream | 作为多线程中数据源:将其与FilterInputStream 对象相连以提供有用接口 |
SequenceInputStream | 将两个或多个InputStream 对象转换成单一InputStream | 两个InputStream 对象或一个容纳InputStream 对象的集合Enumeration | 作为一种数据源:将其与FilterInputStream 对象相连以提供有用接口 |
FilterInputStream | 抽象类,作为“装饰器”的接口,其中,“装饰器”为其他的InputStream 类提供有用功能 | 见表2 | 见表2 |
类 | 功能 | 构造器 | 如何使用 |
---|---|---|---|
DataInputStream | 与DataOutputStream 搭配使用,因此我们可以按照可移植方式从流读取基本数据类型 | InputStream | 包含用于读取基本类型数据的全部接口 |
BufferedInputStream | 使用它可以防止每次读取时都得尽兴实际写操作。代表“使用缓冲区” | InputStream ,可以指定缓冲区大小(可选的) | 本质上不提供接口,只不过是向进程中添加缓冲区所必需的。与接口对象搭配 |
LineNumberInputStream | 跟踪输入流中的行号,可调用getLineNumber() 和setLineNumber(int) | InputStream | 仅增加了行号,因此可能要与接口对象搭配使用 |
PushbackInputStream | 具有“能弹出一个字节的缓冲区”。因此可以将读到的最后一个字符退回 | InputStream | 通常作为编译器的扫描器,之所以包含在内是因为Java编译器的需要,我们可能永远不会用到 |
2.OutputStream
类 | 功能 | 构造器 | 如何使用 |
---|---|---|---|
ByteArrayOutputStream | 在内存中创建缓冲区,所有送往“流”的数据都要放置在次缓冲区 | 缓冲区初始化尺寸(可选的) | 用于指定数据的目的地:将其与FilterOutputStream 对象相连以提供有用接口 |
FileOutputStream | 用于将信息写至文件 | 字符串,表示文件名、文件或FileDescriptor 对象 | 指定数据的目的地:将其与FilterOutputStream 对象相连以提供有用接口 |
PipedOutputStream | 任何写入其中的信息都会自动作为相关PipedInputStream 的输出,实现“管道化”概念 | PipedInputStream | 指定用于多线程的数据的目的地:将其与FilterOutputStream 对象相连以提供有用接口 |
FilterOutputStream | 抽象类,作为“装饰器”的接口,其中,“装饰器”为其他的OutputStream 类提供有用功能 | 见表4 | 见表4 |
类 | 功能 | 构造器 | 如何使用 |
---|---|---|---|
DataOutputStream | 与DataInputStream 搭配使用,因此我们可以按照可移植方式向流中写入基本数据类型 | OutputStream | 包含用于写入基本类型数据的全部接口 |
PrintStream | 用于产生格式化输出。其中DataOutputStream 处理数据的存储,PrintStream 处理显示 | OutputStream ,可以用boolean 值指示是否在每次转换时晴空缓冲区(可选的)应该是对OutputStream 对象的“final ”封装 | 可能会经常使用它 |
BufferedOutputStream | 使用它避免每次发送数据时都要进行实际的写操作。代表“使用缓冲区”。可以调用flush() 清空缓冲区 | OutputStream 可以指定缓冲区大小(可选的) | 本质上并不提供接口,只不过是向进程中添加缓冲区所必需的。与接口对象搭配 |
三、Reader和Writer
当我们首次看见Reader
和Writer
时,可能会以为这是两个用来替代InputStream
和OutputStream
的类,但实际上并非如此,InputStream
和OutputStream
面向字节,而Reader
和Writer
面向字符。
有时我们必须把来自与“字节“层次结构中的类和”字符”层次结构中的类结合起来使用,为了实现这个目的,要用到“适配器”类:InputStreamReader
可以把InputStream
转换成Reader
,而OutputStreamWriter
可以把OutputStream
转换成Writer
。设计Reader
和Writer
层次结构主要是为了国际化。