File类是Java中IO部分的一个类,用于表示文件或者目录的。关于File类有很多的常规操作这里就不介绍了,来看一下不常规的东西。
File英文意思是文件,但是它也可以用来表示目录,文件的概念还是比较广的。
public class File implements Serializable, Comparable<File>
File类实现的Comparable接口
File类实现了Serializable和Comparable接口,可是为什么要实现Comparable接口呢?
/** * 比较两个抽象路径的字典序. 比较的结果依赖于底层的文件系统. * 在UNIX上路径是大小写敏感的, 在Microsoft Windows系统上则不是. * * @param pathname The abstract pathname to be compared to this abstract * pathname * * @return Zero if the argument is equal to this abstract pathname, a * value less than zero if this abstract pathname is * lexicographically less than the argument, or a value greater * than zero if this abstract pathname is lexicographically * greater than the argument * * @since 1.2 */ public int compareTo(File pathname) { return fs.compare(this, pathname); }
这就要看一下接口中的方法是干啥的。然后这就要和文件系统有关系。
其中有个fs.compare(),这个是文件系统对象的比较方法
File类中有一个关于文件系统的引用
abstract class FileSystem; // 一个抽象类表示文件系统
然后一个类是DefaultFileSystem,这个类中有一个静态方法返回本地默认的文件系统。
class DefaultFileSystem { /** * Return the FileSystem object for Windows platform. */ public static FileSystem getFileSystem() { return new WinNTFileSystem(); } }
然后这个WinNTFileSystem继承的是抽象的FileSystem:
class WinNTFileSystem extends FileSystem;
WinNTFileSystem的compare方法为:
@Override public int compare(File f1, File f2) { return f1.getPath().compareToIgnoreCase(f2.getPath()); }
final和static配合使用
final表示的对象是不可变的,但是有时候我们需要根据情况来初始化final属性。这里在File类中用的方法就是static代码段。
private static final long PATH_OFFSET; private static final long PREFIX_LENGTH_OFFSET; private static final sun.misc.Unsafe UNSAFE; static { try { sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe(); PATH_OFFSET = unsafe.objectFieldOffset( File.class.getDeclaredField("path")); PREFIX_LENGTH_OFFSET = unsafe.objectFieldOffset( File.class.getDeclaredField("prefixLength")); UNSAFE = unsafe; } catch (ReflectiveOperationException e) { throw new Error(e); } }
前面三个final属性没有在定义的时候进行初始化,而是在static代码中进行的。这个可以借鉴一下哦。
文件过滤器
在列举一个目录的文件的时候使用了文件过滤器:
public File[] listFiles(FilenameFilter filter) { String ss[] = list(); if (ss == null) return null; ArrayList<File> files = new ArrayList<>(); for (String s : ss) if ((filter == null) || filter.accept(this, s)) files.add(new File(s, this)); return files.toArray(new File[files.size()]); }
先是由list方法列举这个文件下所有的文件(包括目录),然后将文件过滤器用于文件的过滤。
这也算一个小的设计模式吧。
文件删除的钩子
这个也可以学习一下,在虚拟机退出的时候如果干一点事的。
在File类中的:
public void deleteOnExit() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkDelete(path); } if (isInvalid()) { return; } DeleteOnExitHook.add(path); }
package java.io; import java.util.*; import java.io.File; /** * 虚拟机关闭时删除文件的钩子 * 使用LinkedHashSet可以防止同名文件的二次插入, 同时可以快速移除 */ class DeleteOnExitHook { private static LinkedHashSet<String> files = new LinkedHashSet<>(); static { // DeleteOnExitHook必须是最后一个被激活的关闭虚拟机的钩子. sun.misc.SharedSecrets.getJavaLangAccess() .registerShutdownHook(2 /* Shutdown hook invocation order */, true /* register even if shutdown in progress */, new Runnable() { public void run() { runHooks(); } } ); } private DeleteOnExitHook() {} // 这是一个将文件添加到删除列表的同步方法 static synchronized void add(String file) { // 判断DeleteOnExitHook是否正在运行中 if(files == null) { // DeleteOnExitHook正在运行中, 此时已经不能加入到删除文件列表了 throw new IllegalStateException("Shutdown in progress"); } files.add(file); } static void runHooks() { LinkedHashSet<String> theFiles; synchronized (DeleteOnExitHook.class) { theFiles = files; files = null; } ArrayList<String> toBeDeleted = new ArrayList<>(theFiles); // reverse the list to maintain previous jdk deletion order. // 最后进来的首先被删除 Collections.reverse(toBeDeleted); for (String filename : toBeDeleted) { (new File(filename)).delete(); } } }
临时文件内部类
内部类还是挺有用的,在File类中就用到了内部类。
private static class TempDirectory { private TempDirectory() { } // 首先是一个临时目录的生成 private static final File tmpdir = new File(AccessController .doPrivileged(new GetPropertyAction("java.io.tmpdir"))); static File location() { return tmpdir; } // 文件名的生成 private static final SecureRandom random = new SecureRandom(); static File generateFile(String prefix, String suffix, File dir) throws IOException { long n = random.nextLong(); if (n == Long.MIN_VALUE) { n = 0; // corner case } else { n = Math.abs(n); } // Use only the file name from the supplied prefix prefix = (new File(prefix)).getName(); String name = prefix + Long.toString(n) + suffix; File f = new File(dir, name); if (!name.equals(f.getName()) || f.isInvalid()) { if (System.getSecurityManager() != null) throw new IOException("Unable to create temporary file"); else throw new IOException("Unable to create temporary file, " + f); } return f; } }
总结一下:
1. Comparable接口以及文件系统的封装
2. final和static的配合使用
3. 文件过滤器
4. 文件删除的钩子
5. 内部类的使用