javaIO -- File源码
一、简介
文件和目录路径名的抽象表示。
用户界面和操作系统使用依赖于系统的路径名字符串命名文件和目录。 这个类提供了一个抽象的,独立于系统的层次化路径名的视图。
二、代码
(一)、属性详情
//平台的本地文件系统的FileSystem对象 private static final FileSystem fs = DefaultFileSystem.getFileSystem(); //这个抽象路径名是规范化的路径名字符串。规范化的路径名字符串使用默认的名称分隔符,不包含任何重复或冗余的分隔符。 private final String path; //表示文件路径状态的枚举类型。 private static enum PathStatus { INVALID, CHECKED }; //指示文件路径是否无效的标志 private transient PathStatus status = null; //抽象路径名前缀的长度,如果没有前缀则为零。 private final transient int prefixLength; //依赖于系统的默认名称分隔符 public static final char separatorChar = fs.getSeparator(); //系统相关的默认名称分隔符 public static final String separator = "" + separatorChar; //系统相关的路径分隔符 public static final char pathSeparatorChar = fs.getPathSeparator(); //系统相关的路径分隔符,用字符串表示 public static final String pathSeparator = "" + pathSeparatorChar;
//私有属性,待完善
private static final long PATH_OFFSET;
private static final long PREFIX_LENGTH_OFFSET;
private static final sun.misc.Unsafe UNSAFE;
private static final long serialVersionUID = 301077366599181567L
private volatile transient Path filePath;
(二)、构造函数
//私有构造器 private File(String pathname, int prefixLength) { this.path = pathname; this.prefixLength = prefixLength; } //私有 private File(String child, File parent) { assert parent.path != null; assert (!parent.path.equals("")); this.path = fs.resolve(parent.path, child); this.prefixLength = parent.prefixLength; } //创建路径名称为pathName的文件实例 public File(String pathname) { if (pathname == null) { throw new NullPointerException(); } this.path = fs.normalize(pathname);//调用路径:FileSystem.normalzie()-->WinNTFileSystem.normalzie() this.prefixLength = fs.prefixLength(this.path); }
/* 注意:双参数文件构造函数不会将空的父抽象路径名解释为当前用户目录。
相反,空的父目录会根据文件系统定义的系统相关目录解析子目录。
getDefaultParent方法。在Unix这个默认值是“/”,而在Microsoft Windows上是“\\”。
为了与这个类的原始行为兼容,需要这样做 */
//从父路径名字符串和子路径名字符串创建一个新的文件实例 public File(String parent, String child) { if (child == null) { throw new NullPointerException(); } if (parent != null) { if (parent.equals("")) { this.path = fs.resolve(fs.getDefaultParent(), fs.normalize(child)); } else { this.path = fs.resolve(fs.normalize(parent), fs.normalize(child)); } } else { this.path = fs.normalize(child); } this.prefixLength = fs.prefixLength(this.path); } //从父抽象路径名和子路径名字符串创建一个新的文件实例。 public File(File parent, String child) { if (child == null) { throw new NullPointerException(); } if (parent != null) { if (parent.path.equals("")) { this.path = fs.resolve(fs.getDefaultParent(), fs.normalize(child)); //路径标准规范化 } else { this.path = fs.resolve(parent.path, fs.normalize(child)); //路径标准规范化 } } else { this.path = fs.normalize(child); } this.prefixLength = fs.prefixLength(this.path); } //通过将给定的文件URI转换为一个抽象路径名,创建一个新的文件实例。 public File(URI uri) { // 检查我们的许多先决条件 if (!uri.isAbsolute()) throw new IllegalArgumentException("URI is not absolute"); if (uri.isOpaque()) throw new IllegalArgumentException("URI is not hierarchical"); String scheme = uri.getScheme(); if ((scheme == null) || !scheme.equalsIgnoreCase("file")) throw new IllegalArgumentException("URI scheme is not \"file\""); if (uri.getAuthority() != null) throw new IllegalArgumentException("URI has an authority component"); if (uri.getFragment() != null) throw new IllegalArgumentException("URI has a fragment component"); if (uri.getQuery() != null) throw new IllegalArgumentException("URI has a query component"); String p = uri.getPath(); if (p.equals("")) throw new IllegalArgumentException("URI path component is empty"); // Ok, 现在初始化 p = fs.fromURIPath(p); if (File.separatorChar != '/') p = p.replace('/', File.separatorChar); this.path = fs.normalize(p); this.prefixLength = fs.prefixLength(this.path); }
(三)、FileSystem 和 WinNTFileSystem
我们在属性和构造函数中发现,多次用到fs即FileSystem这个类,在File众多方法中也使用了FileSystem的实例,说明File类的很多功能是调用FileSystem这个类完成的。接下来 具体学习此类。
FileSystem和WinNTFileSystem到底是什么?
* 操作系统有各自的文件系统,这些文件系统又存在很多差异,而Java 因为是跨平台的,所以它必须要统一处理这些不同平台文件系统之间的差异,才能往上提供统一的入口。
* 说白了又是接口来实现统一,不同的操作系统实现这个接口,就可以提供统一的表现形式。
* FileSystem是一个抽象类。它的实现类是WinNTFileSystem。FileSystem大部分功能都是通过这个类实现的。
* 如果你目前只看到了一个WinNTFileSystem 那说明你在Windows环境下,只能在 Windows 版本的 JDK 中找到 WinNTFileSystem,而在 Linux 版本的 JDK 中找到 UnixFileSystem
同样地,其他操作系统也有自己的文件系统实现类。
具体这两个类的介绍:https://www.cnblogs.com/noteless/p/9609837.html#11
(四)、路径内容访问器(Path-component accessors)
//返回文件或目录的名称。如果路径名的名称序列为空,则返回空字符串。 public String getName() { int index = path.lastIndexOf(separatorChar); //返回分隔符在路径最后的位置下标 if (index < prefixLength) return path.substring(prefixLength); //如果下标小于路径前缀,则直接返回前缀 return path.substring(index + 1); //下标大于前缀,则截取下标之前的内容 } //返回路径名的父路径名字符串,若无父路径,返回null public String getParent() { int index = path.lastIndexOf(separatorChar);//分隔符最后一次位置下标 if (index < prefixLength) { //下标小于前缀长度 if ((prefixLength > 0) && (path.length() > prefixLength)) //前缀长度 > 0 && 总路径长度 > 前缀长度 return path.substring(0, prefixLength); //截取前缀字符串,即是父路径 return null; } return path.substring(0, index); // 下标 > 前缀长度 } //返回父目录的File实例 public File getParentFile() { String p = this.getParent();//获取父路径 if (p == null) return null; //为空返回空 return new File(p, this.prefixLength); //新建父目录File实例 } //将此抽象路径名转换为路径名字符串。 public String getPath() { return path; }
(五)、路径操作(Path operations)
//是否为绝对路径 public boolean isAbsolute() { return fs.isAbsolute(this); } //返回绝对路径字符串 public String getAbsolutePath() { return fs.resolve(this); } //返回绝对路径的File实例 public File getAbsoluteFile() { String absPath = getAbsolutePath(); return new File(absPath, fs.prefixLength(absPath)); //创建绝对路径的实例 } //返回规范路径名,字符串 public String getCanonicalPath() throws IOException { if (isInvalid()) { //检查文件是否有无效路径 throw new IOException("Invalid file path"); } return fs.canonicalize(fs.resolve(this)); } //返回路径名规范形式的File实例 public File getCanonicalFile() throws IOException { String canonPath = getCanonicalPath(); return new File(canonPath, fs.prefixLength(canonPath)); } //返回路径标准的分隔符(斜线"/") private static String slashify(String path, boolean isDirectory) { String p = path; if (File.separatorChar != '/') //如果分隔符不是“/”,将其替换 p = p.replace(File.separatorChar, '/'); if (!p.startsWith("/")) p = "/" + p; if (!p.endsWith("/") && isDirectory) p = p + "/"; return p; } //将此抽象路径名转换为URL对象。URL的确切形式依赖于系统。 @Deprecated public URL toURL() throws MalformedURLException { if (isInvalid()) { throw new MalformedURLException("Invalid file path"); } return new URL("file", "", slashify(getAbsolutePath(), isDirectory())); } //创建一个URI实例。 public URI toURI() { try { File f = getAbsoluteFile(); String sp = slashify(f.getPath(), f.isDirectory()); if (sp.startsWith("//")) sp = "//" + sp; return new URI("file", null, sp, null); } catch (URISyntaxException x) { throw new Error(x); // Can't happen } }
(六)、属性访问操作
//是否有读权限 public boolean canRead() { SecurityManager security = System.getSecurityManager(); //SecurityManager安全管理器 if (security != null) { security.checkRead(path); } if (isInvalid()) { return false; } return fs.checkAccess(this, FileSystem.ACCESS_READ); } //是否有写权限 public boolean canWrite() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkWrite(path); } if (isInvalid()) { return false; } return fs.checkAccess(this, FileSystem.ACCESS_WRITE); } //是否存在 public boolean exists() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(path); } if (isInvalid()) { return false; } return ((fs.getBooleanAttributes(this) & FileSystem.BA_EXISTS) != 0); } //是否为目录文件夹 public boolean isDirectory() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(path); } if (isInvalid()) { return false; } return ((fs.getBooleanAttributes(this) & FileSystem.BA_DIRECTORY) != 0); } //是否为文件 public boolean isFile() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(path); } if (isInvalid()) { return false; } return ((fs.getBooleanAttributes(this) & FileSystem.BA_REGULAR) != 0); } //此文件是否为隐藏文件 public boolean isHidden() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(path); } if (isInvalid()) { return false; } return ((fs.getBooleanAttributes(this) & FileSystem.BA_HIDDEN) != 0); } //最后修改时间 public long lastModified() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(path); } if (isInvalid()) { return 0L; } return fs.getLastModifiedTime(this); } //文件长度。 是内容?还是路径长度?待完善 public long length() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(path); } if (isInvalid()) { return 0L; } return fs.getLength(this); }
(七)、文件操作(File operations)
//创建文件 public boolean createNewFile() throws IOException { SecurityManager security = System.getSecurityManager(); //java安全管理器 if (security != null) security.checkWrite(path); if (isInvalid()) { //路径是否有效 throw new IOException("Invalid file path"); } return fs.createFileExclusively(path); } //删除空目录或文件 public boolean delete() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkDelete(path); } if (isInvalid()) { return false; } return fs.delete(this); } //请求在虚拟机终止时删除由此抽象路径名表示的文件或目录。不常用且慎用 public void deleteOnExit() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkDelete(path); } if (isInvalid()) { return; } DeleteOnExitHook.add(path); } //返回该目录下的文件和目录的字符串数组。 public String[] list() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(path); } if (isInvalid()) { return null; } return fs.list(this); } // public String[] list(FilenameFilter filter) { String names[] = list(); if ((names == null) || (filter == null)) { return names; } List<String> v = new ArrayList<>(); for (int i = 0 ; i < names.length ; i++) { if (filter.accept(this, names[i])) { v.add(names[i]); } } return v.toArray(new String[v.size()]); } //返回该目录下File实例数组 public File[] listFiles() { String[] ss = list(); if (ss == null) return null; int n = ss.length; File[] fs = new File[n]; for (int i = 0; i < n; i++) { fs[i] = new File(ss[i], this); } return fs; } // 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()]); } // public File[] listFiles(FileFilter filter) { String ss[] = list(); if (ss == null) return null; ArrayList<File> files = new ArrayList<>(); for (String s : ss) { File f = new File(s, this); if ((filter == null) || filter.accept(f)) files.add(f); } return files.toArray(new File[files.size()]); } //创建文件夹 public boolean mkdir() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkWrite(path); } if (isInvalid()) { return false; } return fs.createDirectory(this); } //创建多层文件夹 public boolean mkdirs() { if (exists()) { return false; } if (mkdir()) { return true; } File canonFile = null; try { canonFile = getCanonicalFile(); } catch (IOException e) { return false; } File parent = canonFile.getParentFile(); return (parent != null && (parent.mkdirs() || parent.exists()) && canonFile.mkdir()); } //重命名 public boolean renameTo(File dest) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkWrite(path); security.checkWrite(dest.path); } if (dest == null) { throw new NullPointerException(); } if (this.isInvalid() || dest.isInvalid()) { return false; } return fs.rename(this, dest); } //设置最后一次修改时间 public boolean setLastModified(long time) { if (time < 0) throw new IllegalArgumentException("Negative time"); //时间大于0 SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkWrite(path); } if (isInvalid()) { return false; } return fs.setLastModifiedTime(this, time); } //将文件或目录设置为 只读权限 public boolean setReadOnly() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkWrite(path); } if (isInvalid()) { return false; } return fs.setReadOnly(this); } //设置此文件只有所有者或者每个人有 写入权限。每个人或所有者通过ownerOnly参数决定 public boolean setWritable(boolean writable, boolean ownerOnly) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkWrite(path); } if (isInvalid()) { return false; } return fs.setPermission(this, FileSystem.ACCESS_WRITE, writable, ownerOnly); } //设置此文件有写入权限 public boolean setWritable(boolean writable) { return setWritable(writable, true); } //设置此文件只有所有者或每个人 有读权限。权限范围又参数ownerOnly决定 public boolean setReadable(boolean readable, boolean ownerOnly) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkWrite(path); } if (isInvalid()) { return false; } return fs.setPermission(this, FileSystem.ACCESS_READ, readable, ownerOnly); } //设置读权限 public boolean setReadable(boolean readable) { return setReadable(readable, true); } //设置执行权限。范围:所有者或每个人,有参数ownerOnly决定 public boolean setExecutable(boolean executable, boolean ownerOnly) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkWrite(path); } if (isInvalid()) { return false; } return fs.setPermission(this, FileSystem.ACCESS_EXECUTE, executable, ownerOnly); } //设置执行权限 public boolean setExecutable(boolean executable) { return setExecutable(executable, true); } //是否有执行权限 public boolean canExecute() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkExec(path); } if (isInvalid()) { return false; } return fs.checkAccess(this, FileSystem.ACCESS_EXECUTE); }
(八)、磁盘使用情况(Disk usage)
//通过此抽象路径名返回分区 named的大小 public long getTotalSpace() { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("getFileSystemAttributes")); sm.checkRead(path); } if (isInvalid()) { return 0L; } return fs.getSpace(this, FileSystem.SPACE_TOTAL); } //返回分区未分配的字节数 named此抽象路径名 public long getFreeSpace() { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("getFileSystemAttributes")); sm.checkRead(path); } if (isInvalid()) { return 0L; } return fs.getSpace(this, FileSystem.SPACE_FREE); } //返回上的分区提供给该虚拟机的字节数 named此抽象路径名。 public long getUsableSpace() { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("getFileSystemAttributes")); sm.checkRead(path); } if (isInvalid()) { return 0L; } return fs.getSpace(this, FileSystem.SPACE_USABLE); }
(九)、临时文件
//临时文件夹内部类
private static class TempDirectory { private TempDirectory() { } // temporary directory location临时目录位置 private static final File tmpdir = new File(AccessController .doPrivileged(new GetPropertyAction("java.io.tmpdir"))); static File location() { return tmpdir; } // file name generation 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; } } //创建临时文件 public static File createTempFile(String prefix, String suffix, File directory) throws IOException { if (prefix.length() < 3) throw new IllegalArgumentException("Prefix string too short"); if (suffix == null) suffix = ".tmp"; File tmpdir = (directory != null) ? directory : TempDirectory.location(); SecurityManager sm = System.getSecurityManager(); File f; do { f = TempDirectory.generateFile(prefix, suffix, tmpdir); if (sm != null) { try { sm.checkWrite(f.getPath()); } catch (SecurityException se) { // don't reveal temporary directory location if (directory == null) throw new SecurityException("Unable to create temporary file"); throw se; } } } while ((fs.getBooleanAttributes(f) & FileSystem.BA_EXISTS) != 0); if (!fs.createFileExclusively(f.getPath())) throw new IOException("Unable to create temporary file"); return f; } //创建临时文件 public static File createTempFile(String prefix, String suffix) throws IOException { return createTempFile(prefix, suffix, null); }
(十)、基础设施
public int compareTo(File pathname) { return fs.compare(this, pathname); } public boolean equals(Object obj) { if ((obj != null) && (obj instanceof File)) { return compareTo((File)obj) == 0; } return false; } public int hashCode() { return fs.hashCode(this); } public String toString() { return getPath(); } private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { s.defaultWriteObject(); s.writeChar(separatorChar); // Add the separator character } private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { ObjectInputStream.GetField fields = s.readFields(); String pathField = (String)fields.get("path", null); char sep = s.readChar(); // read the previous separator char if (sep != separatorChar) pathField = pathField.replace(sep, separatorChar); String path = fs.normalize(pathField); UNSAFE.putObject(this, PATH_OFFSET, path); UNSAFE.putIntVolatile(this, PREFIX_LENGTH_OFFSET, fs.prefixLength(path)); }