Java8 File / FileSystem(一) 源码解析

目录

1、separator / pathSeparatorChar

 2、构造方法

 3、isAbsolute / getAbsolutePath / getCanonicalPath 

4、exists / isDirectory / isFile / isHidden / lastModified / length

5、createNewFile / createTempFile / delete / deleteOnExit

6、mkdir / mkdirs

7、list / listFiles / listRoots


     File表示文件系统中的一个文件,提供了文件操作的相关API,其底层实现都是通过FileSystem实现的。FileSystem表示底层操作系统的一个文件系统,windows下的实现是WinNTFileSystem,类Unix系统下的实现是UnixFileSystem,我们重点关注后者的实现细节。

1、separator / pathSeparatorChar

    这两个是File类的public static属性,分别表示路径分隔符和多个路径字符串的分隔符,其定义如下:

//路径分隔符,对应系统属性file.separator
public static final String separator = "" + separatorChar;

public static final char separatorChar = fs.getSeparator();

//多个路径字符串的分隔符,对应系统属性path.separator
public static final String pathSeparator = "" + pathSeparatorChar;

public static final char pathSeparatorChar = fs.getPathSeparator();

//fs表示文件系统的实现
private static final FileSystem fs = DefaultFileSystem.getFileSystem();


//slash和colon都是UnixFileSystem的私有属性,在构造方法中完成初始化
public char getSeparator() {
        return slash;
}

public char getPathSeparator() {
        return colon;
    }

public UnixFileSystem() {
        //读取对应的系统属性
        slash = AccessController.doPrivileged(
            new GetPropertyAction("file.separator")).charAt(0);
        colon = AccessController.doPrivileged(
            new GetPropertyAction("path.separator")).charAt(0);
        javaHome = AccessController.doPrivileged(
            new GetPropertyAction("java.home"));
    }

 window下DefaultFileSystem的实现如下:

类Unix下DefaultFileSystem的实现如下,其源码在jdk\src\solaris\classes\java\io目录下:

测试用例如下:

import java.io.File;

public class FileTest {

    public static void main(String[] args) {
        //windows下文件路径
//        File file=new File("D:\\export\\data\\test.txt");
        //Linux下的文件路径
        File file=new File("/export/data/test.txt");
        System.out.println(file.getName());
        System.out.println("separator->"+File.separator);
        System.out.println("pathSeparator->"+File.pathSeparator);

}

window下输出如下:

Linux下输出如下:

 2、构造方法

public File(String pathname) {
        if (pathname == null) {
            throw new NullPointerException();
        }
        //将文件路径转换成正常格式
        this.path = fs.normalize(pathname);
        //获取路径前缀的长度,Linux下如果以/开始则prefixLength是1,否则是0,
        //windows下需要计算包含前面盘符在内的前缀的长度
        this.prefixLength = fs.prefixLength(this.path);
    }

public File(String parent, String child) {
        if (child == null) {
            throw new NullPointerException();
        }
        if (parent != null) {
            if (parent.equals("")) {
                //父路径为空,则使用默认的父路径,Linux下是/
                //resolve返回该父路径下某个子路径的真实路径
                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);
    }

public File(URI uri) {

        //检查uri是否符合file类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");

        //计算路径
        p = fs.fromURIPath(p);
        if (File.separatorChar != '/')
            p = p.replace('/', File.separatorChar);
        this.path = fs.normalize(p);
        this.prefixLength = fs.prefixLength(this.path);
    }

//去掉路径中多余的/
public String normalize(String pathname) {
        int n = pathname.length();
        char prevChar = 0;
        for (int i = 0; i < n; i++) {
            char c = pathname.charAt(i);
            if ((prevChar == '/') && (c == '/')) 
                //如果是连续两个//
                return normalize(pathname, n, i - 1);
            prevChar = c;
        }
        //如果最后一个字符是/
        if (prevChar == '/') return normalize(pathname, n, n - 1);
        return pathname;
    }

//计算路径中前缀字符串的长度
public int prefixLength(String pathname) {
        if (pathname.length() == 0) return 0;
        //如果以/开头则返回1,否则返回0
        return (pathname.charAt(0) == '/') ? 1 : 0;
    }

//计算某个父路径下子路径的完整路径
public String resolve(String parent, String child) {
        //child是空,则直接返回parent
        if (child.equals("")) return parent;
        if (child.charAt(0) == '/') {
            //parent是/
            if (parent.equals("/")) return child;
            return parent + child;
        }
        if (parent.equals("/")) return parent + child;
        return parent + '/' + child;
    }

//去掉路径中多余的/
private String normalize(String pathname, int len, int off) {
        if (len == 0) return pathname;
        int n = len;
        //倒着遍历,找到第一个不是/的字符
        while ((n > 0) && (pathname.charAt(n - 1) == '/')) n--;
        if (n == 0) return "/";
        StringBuffer sb = new StringBuffer(pathname.length());
        //截取0到off之间的字符串
        if (off > 0) sb.append(pathname.substring(0, off));
        char prevChar = 0;
        //遍历off到n之间的字符
        for (int i = off; i < n; i++) {
            char c = pathname.charAt(i);
            //如果是连续多个/则跳过后面的/
            if ((prevChar == '/') && (c == '/')) continue;
            sb.append(c);
            prevChar = c;
        }
        return sb.toString();
    }

public String fromURIPath(String path) {
        String p = path;
        //去掉末尾多余的/
        if (p.endsWith("/") && (p.length() > 1))
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值