文件和目录路径名称的一个抽象表示。
用户接口和操作系统使用依赖系统的路径名称字符串来命名文件和目录。这个File类提供了一个抽象的,与系统无关的层级路径名称视图。一个抽象的路径名称有两个组件:
一个可选的系统依赖的前缀字符串,类似磁盘驱动说明符“/”用于UNIX根目录,或者\\\\
对于Microsoft Windows UNC 路径名,和0或者多个字符串名的序列。
抽象路径名的第一个名称可能是目录名,或者,对于Microsoft Windows UNC路径名,是主机名。抽象路径名的每一个后续名字表示目录;最后一个名称可能表示目录或是文件。空的抽象路径名没有前缀和名字序列是空的。
路径字符串转换成抽象路径名或从抽象路径名转换是固有的与系统相关的。将抽象路径名转换成路径字符串时,每一名称都由默认分隔符的单个副本和下一个名称分开。默认的名称分隔符由系统属性file.separator定义,并且在该类的公开静态字段separator和separatorChar是可用的。将路径名字符串转换成抽象路径名时,其中的名字会被默认名称分隔符或是基础系统支持的任何其他名称分隔符分隔。
路径名,无论是抽象的或是字符串形式,可能是绝对的或是相对的。绝对路径名是完整的,因为不需要其他的信息去定位它表示的文件。相对路径名,相反,必须从其他路径名获取信息来解释。默认情况下,java.io包下的类总是针对当前用户的目录解析相对的路径名。系统属性user.dir命名目录,并且通常调用Java虚拟机的目录。
调用该类的方法getParent可以获得抽象路径名的父项,并且包括路径名的前缀和路径名字序列除最后一个的每个名字。每一个目录的绝对路径名是任何具有绝对抽象路径名的File对象的祖先,其中绝对抽象路径名以目录的绝对路径名开始。例如,抽象路径名是”/usr”的目录是路径名是”/usr/local/bin”的目录的祖先。
前缀的概念是用来处理UNIX平台的根目录和驱动分隔符,根目录和在Microsoft Windows 平台的UNC路径名,如下:
对于UNIX平台,绝对路径名的前缀总是”/”。相对的路径名没有前缀。这个抽象的路径名表示根路径有前缀“/”和一个空的名字序列。
对于Microsoft Windows平台,包括驱动说明符的路径名的前缀由驱动字符加上”:”组成,如果路径名是绝对的,可能加上”\”。UNC路径名的前缀是\\\\
;主机名和共享名称是名字序列的前两个名字。没有指定驱动器的相对路径名没有前缀。
File的实例可能表示一个实际的文件系统对象例如文件或是目录。如果这个File表示了这样一个对象,这个对象驻留在一个分区中。分区是文件系统的操作系统的指定存储部分。一个单个的存储设备(例如,物理磁盘驱动器,闪存,CD-ROM)可能包括多个分区。这个对象,如果有的话,会驻留在该路径名的绝对形式的某个祖先命名的分区上。
文件系统可以对实际文件系统的对象的某些操作实施限制,类似读,写和执行。这个限制统称为访问权限。文件系统可能对单个对象设置了多个访问权限。例如,设置了一个应用在对象的拥有者,和另一个应用在其他所有的使用者。这个对象的访问权限可能会导致这个类的一些方法失败。
File类的实例是一成不变的;也就是说,一旦创建,一个文件对象表示的抽象路径名是永远不会改变的。
与java.nio.file包的互操作性
java.nio.file包定义了Java虚拟机的接口和类来访问文件,文件属性,和文件系统。这个API可能用来克服java.io.File类的很多限制。toPath方法用来获取路径,用一个对象表示的抽象路径来定位文件。由此产生的路径Path可以用来和java.nio.file.Files类一起使用,用来提供对额外的文件操作,文件属性和I/O异常更有效和广泛的访问,来帮助诊断文件操作失败。
public class File implements Serializable, Comparable<File>
File类实现了Serializable和Comparable接口
private static final FileSystem fs = DefaultFileSystem.getFileSystem();
FileSystem对象代表平台的本地文件系统。
private final String path;
抽象的路径名的规范化的路径名字符串。规范化的路径名字符串使用默认的名称分隔符字符和不包括重复或是冗余的分隔符。
private static enum PathStatus { INVALID, CHECKED };
枚举类型显示文件路径的状态。
private transient PathStatus status = null;
这个标志表示文件路径是否是无效的。
final boolean isInvalid() {
if (status == null) {
status = (this.path.indexOf('\u0000') < 0) ? PathStatus.CHECKE : PathStatus.INVALID;
}
return status == PathStatus.INVALID;
}
检查文件是否具有无效的路径。目前,文件路径的检查是非常有限的,并且只是覆盖了Null字符检查。返回true表示路径是绝对无效/垃圾。但是返回false不能保证路径是有效的。
private final transient int prefixLength;
抽象路径名前缀的长度,当没有前缀的时候,为0。
int getPrefixLength() {
return prefixLength;
}
返回该抽象路径名前缀的长度,供FileSystem类使用。
public static final char separatorChar = fs.getSeparator();
系统相关的默认名称分隔符字符。这个字段初始化来包括系统属性file.separator值的第一个字符。对于UNIX系统,这个字段的值是’/’;对Microsoft Windows 系统,是\\
。
public static final String separator = "" + separatorChar;
系统相关的默认的命名分隔符字符,为了方便以字符串表示。这个字符串包括单个字符,即separatorChar。
public static final char pathSeparatorChar = fs.getPathSeparator();
系统相关的路径分隔符字符。这个字段被初始化来包括系统属性path.separator的值的第一个字符。这个字符用来分隔作为路径列表给出的一系列文件的文件名。对于UNIX系统,这个字符是’:’;对于Microsoft Windows系统,是’;’。
public static final String pathSeparator = "" + pathSeparatorChar;
系统相关的路径分隔符字符,为了方便表示一个字符串。这个字符串包括单个字符,即pathSeparatorChar。
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;
}
已经规范化的路径名字符串的内部构造函数。这个参数的顺序是用来消除public(File,String)这个方法的歧义。
public File(String pathname) {
if (pathname == null) {
throw new NullPointerException();
}
this.path = fs.normalize(pathname);
this.prefixLength = fs.prefixLength(this.path);
}
通过将给定的路径名字符串转化为抽象路径名来创建一个新的File实例。如果给定字符串是空字符串,结果是空的抽象路径名。
注:两个参数的文件构造函数不会将空的父抽象路径名解释为当前用户目录。空的父项通过FileSystem.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);
}
从父路径名字符串和子路径名字符串创建一个新的File实例。
如果父项是空,通过调用给定的子路径名字符串上的单个参数File构造函数来创建File实例。
否则父路径名字符串被用来表示目录,和子路径名字符串被用来表示目录或文件。如果子路径名字符串是绝对的,它以系统相关的方式转换成相关的路径名。如果父项是空字符串,通过转换子项为抽象路径名和解决与系统相关的默认目录的结果来创建新的File实例。否则,每一个路径名字符串被转换成抽象路径名和子抽象路径名将被父解析。
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);
}
根据父项抽象的路径名和子项路径名字符串创建一个新的File实例。
如果父项是空,则创建新的File实例,就像调用给定的子路径名字符串上的单参数File构造函数。
否则,父项抽象路径名被用来表示一个目录,并且子路径名字符串被用来表示目录或文件。如果子项路径名字符串是绝对的,它会以系统相关的方式转换成相对的路径名。如果父项是空的抽象路径名,新的File实例是通过将子项转换成抽象路径名和根据系统相关的默认的目录解析结果而创建的。否则,每一个路径名字符串被转换成抽象路径名和子抽象路径名是针对父级解析的。
public File(URI uri) {
// Check our many preconditions
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");
// Okay, now initialize
p = fs.fromURIPath(p);
if (File.separatorChar != '/')
p = p.replace('/', File.separatorChar);
this.path = fs.normalize(p);
this.prefixLength = fs.prefixLength(this.path);
}
通过将给定的file:URI转成抽象路径名来创建一个File实例。
file:URI的转换形式是系统相关的,于是,这个构造函数执行的转换也是系统相关的。
对于给定的抽象路径名,保证new File(toURI())和new File(getAbsoluteFile())是相关的。只要保证原始抽象的路径名,URI和新的抽象路径名是创建在(可能是不同的调用)相同的Java虚拟机。但是,当一个操作系统上的file:URI被转换成不同操作系统上的虚拟机的抽象路径名时,此关系是不成立的。
public String getName() {
int index = path.lastIndexOf(separatorChar);
if (index < prefixLength) return path.substring(prefixLength);
return path.substring(index + 1);
}
返回此抽象路径名表示的文件或目录的名字。这只是路径名称序列中的最后一个名字。如果路径名的名称序列是空的,则会返回空的字符串。
public String getParent() {
int index = path.lastIndexOf(separatorChar);
if (index < prefixLength) {
if ((prefixLength > 0) && (path.length() > prefixLength))
return path.substring(0, prefixLength);
return null;
}
return path.substring(0, index);
}
返回抽象路径名的父项的路径名字符串,当路径名没有命名父目录时,返回空。抽象路径名的父结点由路径名的前缀(如果有),和路径名名称序列中除最后一个以外的每个名字组成。如果名字序列为空,那么路径名不会命名父目录。
public File getParentFile() {
String p = this.getParent();
if (p == null) return null;
return new File(p, this.prefixLength);
}
返回此抽象路径名的父项的抽象路径名,当路径名没有命名父目录时,返回null。
抽象路径名的父项包括路径名的前缀(如果有),和路径名的名称序列除了最后一个的每一个名字。如果名字序列是空的,路径名不会命名父目录。
public String getPath() {
return path;
}
将此抽象路径名转成路径名字符串。结果字符串使用默认的命名的分隔符字符来分割名称序列中的名称。
public boolean isAbsolute() {
return fs.isAbsolute(this);
}
测试抽象路径名是否是绝对的。绝对路径名的定义是系统相关的。在UNIX系统,如果前缀是”/”,路径名是绝对的。在Microsoft Windows系统,如果它的前缀是驱动说明符,后跟”\”,或者它的前缀是\\\\
,路径是绝对的。
public String getAbsolutePath() {
return fs.resolve(this);
}
返回此抽象路径名的绝对路径名字符串。
如果此抽象路径名已经是绝对的,那么路径名字符串就像getPath()方法一样简单返回。如果抽象路径字符串是空的抽象路径字符串,返回的当前用户目录的路径名字符串,是由系统属性user.dir命名的。否则这个路径名以系统相关的方式解析。在UNIX系统,通过针对当前用户目录解析相对路径名是绝对的。在Microsoft Windows系统,通过针对由路径名命名的当前目录的驱动解析相对路径名是绝对的,如果有的话;如果没有,通过针对当前用户目录解析。
如果不能访问要求的系统属性值,会抛出SecurityException。
public File getAbsoluteFile() {
String absPath = getAbsolutePath();
return new File(absPath, fs.prefixLength(absPath));
}
返回抽象路径名的抽象形式。等价于getAbsolutePath()方法。如果不能访问要求的系统属性值,抛出SecurityException。
public String getCanonicalPath() throws IOException {
if (isInvalid()) {
throw new IOException("Invalid file path");
}
return fs.canonicalize(fs.resolve(this));
}
返回此抽象路径名的规范路径名字符串。
规范路径名是绝对的和独特的。规范形式的精确的含义是系统相关的。这个方法首先如果有需要将这个路径名转成绝对形式,就像调用getAbsolutePath()方法,然后将其以系统相关的方式映射成独特的形式。这通常涉及删除多余的名字,类似”.”和”..”的路径名,解析符号链接(在UNIX平台),并将驱动器号转换成标准大小写(在Microsoft Windows平台)。
表示现有文件或目录的每个路径名有独特的规范形式。表示不存在的文件或目录的每一个路径名也有独特的规范形式。不存在的文件或目录的路径名的规范形式可能不同于创建文件或目录后相同路径名的规范形式。相同地,现有的文件或目录的路径名的规范形式可能会不同于在文件或目录删除后相同的路径名的规范形式。
如果出现I/O错误,这是可能的,因为规范的路径名的构建可能需要文件系统查询。如果不能访问要求的系统属性值,或者存在安全管理并且它的java.lang.SecurityManager的checkRead()方法拒绝了这个文件的读访问,会抛出SecurityException。
public boolean canRead() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(path);
}
if (isInvalid()) {
return false;
}
return fs.checkAccess(this, FileSystem.ACCESS_READ);
}
测试应用是否可以读这个抽象的路径名表示的文件。在一些平台可能需要使用特殊权限来开启Java虚拟机,以便读取标志为不可读的文件。所以这个方法可能返回true,尽管这个文件没有读取权限。可能会抛出SecurityException,理由同上。
public boolean canWrite() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkWrite(path);
}
if (isInvalid()) {
return false;
}
return fs.checkAccess(this, FileSystem.ACCESS_WRITE);
}
测试这个应用能否修改此抽象路径名表示的文件一些平台可能需要特殊的权限开启Java虚拟机来修改标志为只读的文件。所以这个方法可能返回true,尽管这个文件标志为只读。可能会抛出SecurityException。
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);
}
检测此抽象路径名表示的文件或目录是否存在。可能会抛出SecurityException。
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);
}
判断此抽象路径名表示的文件是否是目录。在需要区分I/O异常和文件不是目录的情况下,或者同时需要一个文件的多个属性的情况下,可以使用java.nio.file.Files的readAttributes方法。可能会抛出SecurityException。
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);
}
判断此抽象路径名表示的文件是否是普通的文件。如果不是目录,那么就是普通的文件。另外,需要符合其他系统相关的标准。由Java应用创建的任何非目录文件都保证是普通文件。
在需要区分I/O异常和文件不是普通文件的情况下,或者同时需要一个文件的多个属性,可以使用java.nio.file.Files的readAttributes方法。
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);
}
检测此抽象路径名命名的文件是否是隐藏文件。隐藏的确切含义是系统相关的。在UNIX系统,如果名字是以句点符号’.’开头的,这个文件被认为是隐藏的。在Microsoft Windows系统,如果在文件系统中被标志为隐藏,则该文件被认为是隐藏的。
public long lastModified() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(path);
}
if (isInvalid()) {
return 0L;
}
return fs.getLastModifiedTime(this);
}
返回该抽象路径名表示的文件上次修改的时间(一个long类型的值)。在需要区分I/O异常和返回0的情况下,或者在同一时间要求使用同一文件的多个属性时,或者需要上次访问时间或创建时间时,可以使用java.io.file.Files的readAttributes方法。
public long length() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(path);
}
if (isInvalid()) {
return 0L;
}
return fs.getLength(this);
}
返回该抽象路径名表示的文件的长度。如果此路径名表示目录,则返回值是未指定的。