zoukankan      html  css  js  c++  java
  • File类的源码学习


    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. 内部类的使用

  • 相关阅读:
    函数式编程理解
    Java8 lambda表达式10个示例
    MD5进行文件完整性校验的操作方法
    加密算法和MD5等散列算法的区别(转)
    随笔
    瑕疵(bug)严重性定义
    无需Cygwin,如果没有在命令行,Eclipse编NDK
    BZOJ 1878 SDOI 2009 HH项链 树状数组 + 脱机处理
    Teamcity+SVN+VisualStudio在持续集成简明教程
    UVALive3713-Astronauts(2-SAT)
  • 原文地址:https://www.cnblogs.com/tuhooo/p/7858255.html
Copyright © 2011-2022 走看看