IO系列之File

1 File类

1.1 目录列表器

在这里我主要是参考Think in Java的内容从而做的一些总结以及扩展。Java中的IO流的设计应该说是Java中最经典的,最学院式的设计,包括它的整体架构设计以及代码的构造。 
现在让我们开始进行文件过滤吧。说到这里,说一下这个File类,从类名上看,它表示文件的意思,但是这个意思却不是准确的表达它的含义,FilePath应该来说更加的符合,它表示的就是文件的路径。好了,让我们看看当前的文件目录吧。

这个就是当前文件所在的目录。 
好了,让我先列出所有的文件列表吧。

package cn.czg.io;

import java.io.File;

/**
 * 目录列表器
 */
public class DirListDemo {
    public static void main(String[] args) {
        /** 文件表示当前目录*/
        File filePath=new File(".");
        /** 当前目录的文件名称组成一个String[] 数组*/
        String[] list = filePath.list();
        for (String listDir:list) {
            System.out.println(listDir);
            /**
             * .idea
             * pom.xml
             * spring40parent.iml
             * src
             * target
             * 测试.java
             */
        }
    }
}

上面的输出结果和文件的目录是一致的。不带参数的list()方法的功能就是返回一个该目录下的文件名的String数组。

public String[] list() {
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        security.checkRead(path);
    }
    if (isInvalid()) {
        return null;
    }
    return fs.list(this);
}

security是一个安全管理器对象,第一个判断是判断安全管理器是否为空,这个目的是为了分配文件的操作权限,比如读写的权限,第二个判断则是判断文件的路径时候合理或者存在。关于安全管理器我希望在有时间的时候作为单独的一个系列来研究下它的源码。在这里我希望不要深究。

1.2 文件过滤器

在大多的时候我们还是希望得到我们想要的文件,比如后缀是.java结尾的文件,在jdk中,存在着专门的一个接口,就是FilenameFilter.它表示的就是文件过滤器。

@FunctionalInterface
public interface FilenameFilter {

    boolean accept(File dir, String name);
}

当且仅当该文件名称包含在文件列表中,则返回true,其他的返回false.好了,让我们实践一把吧。 
在操作之前,我们来看看file.list()的api 

大家可以清楚的看到,下面的list()方法带有参数,参数是一个filter,即文件过滤器。 
请看如下的代码:

/**
 * 目录列表器
 */
public class DirListDemo {
    public static void main(String[] args) {
        /** 文件表示当前目录*/
        File filePath=new File(".");
        /** 当前目录的文件名称组成一个String[] 数组*/
        //String[] list = filePath.list();
        // list方法包含了所有的文件的名称
        // 如果要调用含有参数的list方法,此时就需要一个FilenameFilter的实现类,并且实现正则匹配
        MyFilenameFilter filter=new MyFilenameFilter(".java");
        String[] list = filePath.list(filter);
        for (String dirList:list) {
            System.out.println(dirList);
        }
    }
}
class MyFilenameFilter implements FilenameFilter{
    private String regex;
    public MyFilenameFilter(String regex) {
        this.regex=regex;
    }

    @Override
    public boolean accept(File dir, String name) {
        return name.endsWith(regex);
    }
}

打印结果毫无疑问的将后缀为Java的文件帅选出来,好了,接着我们可以对刚才的代码进行优化,让它看起来比较完美。 
优化一 匿名内部类:

public class DirListDemo3 {
    public static void main(String[] args) {
        /** 文件表示当前目录*/
        File filePath=new File(".");
        String[] list = filePath.list(filter(".java"));

        for (String dirList:list) {
            System.out.println(dirList);
        }
    }
    public static FilenameFilter filter(String regex){
        return new FilenameFilter() {
            private String regexs=regex;
            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(regexs);
            }
        };
    }
}

大家可以看到,上述的FilenameFilte作为方法的返回值进行了传递,此时FilenameFilte掺杂在DirListDemo3中,所以我们直接将FilenameFilte作为方法的参数直接传递也是可以的,这样也是降低了耦合: 
优化二:FilenameFilte作为参数传递:

public class DirListDemo {
    public static void main(String[] args) {
        /** 文件表示当前目录*/
        File filePath=new File(".");
        String regex=".java";
        String[] list = filePath.list(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(regex);
            }
        });
        for (String dirList:list) {
            System.out.println(dirList);
        }
    }
}

1.3 目录实用工具

现在我的需求就是列出当前文件下的所有的文件或者文件夹 
看到这里我们很容易想到递归的操作方式,确实如此,本例也是使用的递归的算法来完成

public class Directory2 {
    public static void main(String[] args) {
        File file=new File(".");
        list(file);
    }
    public static void list(File file){
        if(file.isDirectory()){
            File[] files = file.listFiles();
            if(files!=null){
                for (int i=0;i<files.length;i++){
                    // 此时files[i]表示的是一个文件或者文件目录
                    //采用递归算法,直接调用list()方法,将files[i]作为参数进行传递
                    list(files[i]);
                }
            }
        }
        System.out.println(file);
    }
}

在Think in java中,封装了一个工具类来完成相同的功能。但是功能要比我上述的写的完全要多。我做了相应的修改,使得代码变得可读性较好

package cn.czg.io;

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Directory {
    /**
     * 该方法返回一个File[]数组,和我们之前的目录列表器是相同的,
     * 通过特定的形式返回特定的文件
     * @param dir
     * @param regex
     * @return
     */
    public static File[] local(File dir,final String regex){
        return dir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(regex);
            }
        });
    }

    /**
     * 该方法和上述的local()方法是方法的重载,只不过此时传递的参数均为字符串,
     * 第一个参数为文件路径的目录的字符串表达形式,第二个参数相同
     * 最后调用第一个local()方法
     * @param path
     * @param regex
     * @return
     */
    public static File[] local(String path,final String regex){
        return local(new File("path"),regex);
    }

    /**
     * 定义一个静态内部类TreeInfo,表示的是文件目录树,实现Iterable,实现此接口的类就可以
     * 成为forech的目标
     */
    public static class TreeInfo implements Iterable<File>{
        /**
         * 定义两个list集合,分别是files(文件list)以及dirs(目录list)
         */
        public List<File> files=new ArrayList<>();
        public List<File> dirs=new ArrayList<>();

        /**
         * 覆盖iterator()方法,返回一个File的比较器
         * @return
         */
        @Override
        public Iterator<File> iterator() {
            return files.iterator();
        }
        void addAll(TreeInfo other){
            /**
             * 将集合files和集合dirs全部添加到对应的list当中
             */

            files.addAll(other.files);
            dirs.addAll(other.dirs);
        }

        @Override
        public String toString() {
            return "TreeInfo{" +
                    "files=" + files +
                    ", dirs=" + dirs +
                    ‘}‘;
        }
    }

    /**
     * 在这里分析下,TreeInfo表示的就是目录树对象,有两个字段
     * files和dirs,这两个集合分别存储文件和目录,而recurseDirs()方法返回的就是TreeInfo对象
     * 这个对象保存了文件和目录,walk()的作用就是执行。
     * @param start
     * @param regex
     * @return
     */
    public static TreeInfo walk(String start,String regex){
        return recurseDirs(new File(start),regex);
    }
    public static TreeInfo walk(File start,String regex){
        return recurseDirs(start,regex);
    }
    public static TreeInfo walk(File start){
        return recurseDirs(start,".*");
    }
    public static TreeInfo walk(String start){
        return recurseDirs(new File(start),".*");
    }

    /**
     *
     * @param startDirs
     * @param regex
     * @return
     */
    static TreeInfo recurseDirs(File startDirs, String regex) {
        TreeInfo result=new TreeInfo();
        for (File item:startDirs.listFiles()) {
            if(item.isDirectory()){
                result.dirs.add(item);
                /**
                 * 递归方法的出口,如果该文件下存在子文件或者子文件夹,
                 * 继续调用recurseDirs()方法,返回的TreeInfo目录树对象添加到
                 * list集合当中
                 */
                result.addAll(recurseDirs(item,regex));
            }else {
                /**
                 * 否则,直接帅选
                 */
                if(item.getName().endsWith(regex))
                    result.files.add(item);

            }
        }
        return result;
    }

    public static void main(String[] args) {
        File[] local = local(new File("."), ".java");
        for (File fs:local) {
            System.out.println(fs);
        }
    }
}

原文地址:https://www.cnblogs.com/gosaint/p/8242824.html

时间: 2024-12-22 21:26:43

IO系列之File的相关文章

java io系列01之 &quot;目录&quot;

javaIO系列转载出处:http://www.cnblogs.com/skywang12345/p/io_01.html 该分类所有博文,均转载同一作者,后边不再累赘标名. java io 系列目录如下: 01. java io系列01之  "目录" 02. java io系列02之 ByteArrayInputStream的简介,源码分析和示例(包括InputStream) 03. java io系列03之 ByteArrayOutputStream的简介,源码分析和示例(包括Ou

java io系列07之 FileInputStream和FileOutputStream

本章介绍FileInputStream 和 FileOutputStream 转载请注明出处:http://www.cnblogs.com/skywang12345/p/io_07.html FileInputStream 和 FileOutputStream 介绍 FileInputStream 是文件输入流,它继承于InputStream.通常,我们使用FileInputStream从某个文件中获得输入字节.FileOutputStream 是文件输出流,它继承于OutputStream.通

io系列之字节流

java中io流系统庞大,知识点众多,作为小白通过五天的视频书籍学习后,总结了io系列的随笔,以便将来复习查看. 本篇为此系列随笔的第一篇:io系列之字节流. 一.字节流的File读写操作. InputStream and OutputStream 一). OutputStream: 字节输出流. 以一个操作文件的例子进行说明: FileOutputStream (说明,该类对象必须指向一个文件,) 构造方法: FileOutputStream(File file) 创建一个向指定 File 对

io系列之字符流

java中io流系统庞大,知识点众多,作为小白通过五天的视频书籍学习后,总结了io系列的随笔,以便将来复习查看. 本篇为此系列随笔的第一篇:io系列之字符流. IO流 :对数据的传输流向进行操作,java中将这种操作行为本身封装为对象,以供使用. Input and Output java将io流对象都在IO包中.(java.IO.*) 分类: 按照数据种类分: 字节流 和 字符流, 按照数据流向分: 输出流 和 输入流. 字节流抽象类: InputStream OutputStream 字符流

java io系列12之 BufferedInputStream详解

目录1. BufferedInputStream 介绍2. BufferedInputStream 源码分析(基于jdk1.7.40)3. 示例代码 BufferedInputStream 是缓冲输入流.它继承于FilterInputStream. BufferedInputStream 的作用是为另一个输入流添加一些功能,例如,提供"缓冲功能"以及支持"mark()标记"和"reset()重置方法".BufferedInputStream 本质

java io系列03之 ByteArrayOutputStream的简介,源码分析和示例(包括OutputStream)

前面学习ByteArrayInputStream,了解了“输入流”.接下来,我们学习与ByteArrayInputStream相对应的输出流,即ByteArrayOutputStream.本章,我们会先对ByteArrayOutputStream进行介绍,在了解了它的源码之后,再通过示例来掌握如何使用它. 转载请注明出处:http://www.cnblogs.com/skywang12345/p/io_03.html ByteArrayOutputStream 介绍 ByteArrayOutpu

java io系列02之 ByteArrayInputStream的简介,源码分析和示例(包括InputStream)

我们以ByteArrayInputStream,拉开对字节类型的“输入流”的学习序幕.本章,我们会先对ByteArrayInputStream进行介绍,然后深入了解一下它的源码,最后通过示例来掌握它的用法. 转载请注明出处:http://www.cnblogs.com/skywang12345/p/io_02.html ByteArrayInputStream 介绍 ByteArrayInputStream 是字节数组输入流.它继承于InputStream.它包含一个内部缓冲区,该缓冲区包含从流

java io系列06之 序列化总结(Serializable 和 Externalizable)

本章,我们对序列化进行深入的学习和探讨.学习内容,包括序列化的作用.用途.用法,以及对实现序列化的2种方式Serializable和Externalizable的深入研究. 转载请注明出处:http://www.cnblogs.com/skywang12345/p/io_06.html 1. 序列化是的作用和用途 序列化,就是为了保存对象的状态:而与之对应的反序列化,则可以把保存的对象状态再读出来. 简言之:序列化/反序列化,是Java提供一种专门用于的保存/恢复对象状态的机制. 一般在以下几种

java io系列05之 ObjectInputStream 和 ObjectOutputStream

本章,我们学习ObjectInputStream 和 ObjectOutputStream ObjectInputStream 和 ObjectOutputStream 介绍 ObjectInputStream 和 ObjectOutputStream 的作用是,对基本数据和对象进行序列化操作支持.创 建“文件输出流”对应的ObjectOutputStream对象,该ObjectOutputStream对象能提供对“基本数据或对象”的持久存储: 当我们需要读取这些存储的“基本数据或对象”时,可以