java File详解

一、简介

   File类是“文件”和“目录名”的抽象表示形式。因此在java语言中,File类既可以表示文件也可以表示目录。

   尽管java.io定义的大多数类是实行流式操作的,而File类则不是,它没有指定信息怎样从文件读取或向文件存储。File描述了文件本身的属性,直接处理文件和文件系统,是唯一一个与文件本身有关的操作。

1.1 File的继承与实现接口

File 直接继承于Object,实现了Serializable接口和Comparable接口。

public class File implements Serializable, Comparable<File>
  • File类实现Serializable接口,意味着File对象支持序列化操作。
  • File类实现Comparable接口,意味着File对象之间可以比较大小,此外File能直接被存储在有序集合(如TreeSet、TreeMap中)。
结构图如下:
image

1.2 File使用注意事项

1、创建File类对象时要注意的地方

    首先我们要区分两个名词:“绝对路径”和“相对路径”。
    绝对路径:即完整的路径,比如:D:\MyCode\Java\FileDemo
    相对路径:会在代码所在的地方生成,比如:res/jay.txt  就会在你代码的目录下成jay.txt文件
   另外,由于路径名字符或者是抽象路径名的转换与生俱来就是依赖于系统的。比如在Unix系统中,绝对路径名的前缀总是“/”,然而在Windows系统中,绝对路径名的前缀总是”\”。
关于前缀的解决办法:
例1:在Windows中,路劲名为D:\Program Files
在java程序中,必须将”\”转换为”/”或者”\\”,比如:D:/Program Files或者D:\\Program Files
 
如果想让程序跨平台的话,由于Linux中是”/”,而Windows中是”\”,我们可以使用File提供的常量字符串File.separator,它能根据系统平台的不同,自动转换成”/”还是”\\”。

1.3 File的常见方法

1)判断文件或者目录是否存在:  exists()

2)判断是否为目录:   isDirectory()

3)判断是否为文件:   isFile()

4)判断文件是否可读:    canRead()

5)判断文件是否可写:    canWrite()

6)判断文件是否隐藏:    isHidden()

7)判断文件路径是否为绝对路径:  isAbsolute()

8)判断文件路径是否相同:  equals():返回true,false       

                                        compareTo():是否相等,相等返回0,小于返回负数,大于返回正数

9)获取文件的绝对路径:   getAbsolutePath()

10)获取文件名称:  getName()

11)获取文件大小:  length()

12)获取文件最后被修改的时间 :  lastModified()

13)获取文件的路径:   getPath()

14)获取文件的上层文件的目录:   getParent()

15)创建一个新文件:    createNewFile()

16)创建一个新目录:    mkdir()

17)删除文件或目录:  delete()

18)修改文件的名称:   renameTo(str)

19)修改文件为只读:  setReadOnly()

20)修改最后的修改时间:   setLastModified(long time)

 

二、源码分析

2.1 成员变量

所有成员变量如下:
image
下面列举一些比较关键的成员变量
// The FileSystem object representing the platform's local file system.
// 获取本地文件系统
private static final FileSystem fs = DefaultFileSystem.getFileSystem();

// 文件路径名
private final String path;

// 标记文件路径是否无效
private transient PathStatus status = null;

// The length of this abstract pathname's prefix, or zero if it has no prefix.
private final transient int prefixLength;

/**
     * The system-dependent default name-separator character.  This field is
     * initialized to contain the first character of the value of the system
     * property <code>file.separator</code>.  On UNIX systems the value of this
     * field is <code>'/'</code>; on Microsoft Windows systems it is <code>'\\'</code>.
     *
*/
public static final char separatorChar = fs.getSeparator();

// The system-dependent path-separator character, represented as a string for convenience.
public static final String pathSeparator = "" + pathSeparatorChar;
1、成员变量 fs 是如何获取到本地文件系统的呢?
Windows平台下,所下载的JDK中,我们找到了WinNTFileSystem文件系统
image
Linux呢?因此,下了个Linux版本的JDK,解压,找到rt.jar。然后java/io目录中,找到了UnixFileSystem类。真相大白了!

S[KM1N]}PTOAHEH_LLMCOZF

其实是根据不同的平台,安装不同版本的JDK,根据平台下对应版本的JDK,加载本地文件系统。

解决了fs这个成员变量,那么separatorChar 这个成员变量就迎刃而解了。

2.2 构造函数

1、首先看看整体如下:

image

2、挑选比较有代表性的方法进行讲解
1) File(String pathname)
public File(String pathname) {
    if (pathname == null) {
        throw new NullPointerException();
    }
    this.path = fs.normalize(pathname);
    this.prefixLength = fs.prefixLength(this.path);
}
该构造方法主要是初始化了path、prefixLength两个成员变量,其中path通过WinNTFileSystem中normalize 公开方法将其规范化。
规范化后的好处,比如

public static void main(String[] args)
{
    File file = new File("d:/test.txt");
    System.out.println(file.getPath());   
}

File:

public String getPath() {
    return path;
}
输出结果:d:\test.txt
主要我们输入的是pathname = "d:/test.txt"  然而path得到的是"d:\test.txt” 。
2)File(File parent, String child)
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);
}
其目的还是为path、prefixLength两个成员变量赋值。
其中,fs.resolve(parent.path,fs.normalize(child));目的就是在合理范围内拼接父与子路径

2.3 创建操作

  • createNewFile
  • createTempFile
  • mkdir

1)createNewFile()

public boolean createNewFile() throws IOException {
    // 1、检查是否有权限对该文件进行操作
    SecurityManager security = System.getSecurityManager();
    if (security != null) security.checkWrite(path);


    // 2、检查文件路径是否有效
    if (isInvalid()) {
        throw new IOException("Invalid file path");
    }


    // 3、在Windows中,调用WinNTFileSystem中createFileExclusively方法,该方法是调用系统底层方法。
    return fs.createFileExclusively(path);
}

 
2)mkdir()
// 此方法创建此抽象路径名的目录。
public boolean mkdir() {
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        security.checkWrite(path);
    }
    if (isInvalid()) {
        return false;
    }
    return fs.createDirectory(this);
}

2.4 删除操作

  • delete
  • deleteOnExit
1)delete()

public boolean delete() {
    // 1、权限检查
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        security.checkDelete(path);
    }



    // 2、检查文件路径是否有效
    if (isInvalid()) {
        return false;
    }
   
    // 3、调用系统本地底层删除方法,
    // 不过在删除之前做了一些清理,cache.clear();prefixCache.clear();
    return fs.delete(this);
}

而deleteOnExit 一般用在删除临时文件。
注意:file.delete()或file.deleteOnExit()方法只能删除文件或空文件夹
2.5 获取文件操作
1)getAbsoluteFile()
// Returns the absolute form of this abstract pathname. Equivalent to new File(this.getAbsolutePath()). 
public File getAbsoluteFile() {
    String absPath = getAbsolutePath();
    return new File(absPath, fs.prefixLength(absPath));
}
2)getCanonicalFile()
// Returns the canonical form of this abstract pathname. Equivalent to new File(this.getCanonicalPath()). 
public File getCanonicalFile() throws IOException {
    String canonPath = getCanonicalPath();
    return new File(canonPath, fs.prefixLength(canonPath));
}
2.6 获取路径操作
1)getAbsolutePath()
// 此方法返回此抽象路径名的绝对路径名字符串。
public String getAbsolutePath() {
    return fs.resolve(this);
}
2)getCanonicalPath()
// 此方法返回此抽象路径名的规范路径名字符串。
public String getCanonicalPath() throws IOException {
    if (isInvalid()) {
        throw new IOException("Invalid file path");
    }
    return fs.canonicalize(fs.resolve(this));
}
3)getPath()
// 此方法此抽象路径名转换为一个路径名字符串。
// Converts this abstract pathname into a pathname string
// 此处pathname与File(String pathname)中pathname一致
public String getPath() {
    return path;
}
4)getParent()
// 此方法返回此抽象路径名的父路径名的字符串,或者null,如果此路径名没有指定父目录。
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);
}
 
由于File中的源码基本上调用系统底层的API,故不再介绍。
 
 
 
 
 
 

 

 
参考:

3、图解 Java IO : 一、File源码

posted @ 2015-09-17 20:26  aoguren  阅读(1613)  评论(0编辑  收藏  举报