文件流-1

对于程序语言的设计者来说,创建一个好的输入输出系统是一个艰巨的任务

File类

File类这个名字有一定的误导性,我们可能会认为它指代的是文件,然而却并非如此,它既能表明一个文件特定的名称,又能代表一个目录下一组文件的名称,如果他指的是文件集,我们就可以对此集合调用list方法,会返回一个字符数组,也及时目录列表


      假设我们想查看一个目录列表,可以用两种方法来使用File对象。如果我们调用不带参数的list0方法,便可以获得此File对象包含的全部列表。然而,如果我们想获得一个受限列表,例如,想得到所有扩展名为java的文件,那么我们就要用到“目录过滤器”,这个类会告诉我们怎样显示符合条件的File对象。

      下面是一一个示例,注意,通过使用java.utils.Arrays.sort和String.CASE INSENSITIVE.ORDERComparator,可以很容易地对结果进行排序(按字母顺序)。


class DirFilter implements FilenameFilter {
    private Pattern p;

    public DirFilter(String regex) {
        p = Pattern.compile(regex);
    }

    @Override
    public boolean accept(File dir, String name) {
        // TODO Auto-generated method stub
        return p.matcher(name).matches();
    }

}

class DirFilter2 {
    // 参数是final是必须的,这是匿名内部类必须的,这样才能使用来自该范围之外的对象
    public static FilenameFilter filter(final String regex) {
        return new FilenameFilter() {

            private Pattern p = Pattern.compile(regex);

            @Override
            public boolean accept(File dir, String name) {
                // TODO Auto-generated method stub
                return p.matcher(name).matches();
            }

        };
    }

}

public class file {
    public static void main(final String[] args) {
        File path = new File(".");
        String[] list;
        if (args.length == 0)
            list = path.list();
        else {
            System.out.println("false");
            // 第一
            list=path.list(new DirFilter(args[0]));//回调,,会调用accept方法
            // 第二
            // list=path.list(DirFilter2.filter(args[0]));
            // 第三,添加final,优点是将解决特定问题的代码隔离,聚拢于一点,但是却不易阅读,要谨慎使用
            /*list = path.list(new FilenameFilter() {

                private Pattern p = Pattern.compile(args[0]);

                @Override
                public boolean accept(File dir, String name) {
                    // TODO Auto-generated method stub
                    return p.matcher(name).matches();
                }
            });*/
        }
        Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
        for (String item : list) {
            System.out.println(item);
        }
    }

    /**
     * 得到指定路径下的文件列表
     * 
     * @param path
     */
    public void getFileList(String path) {
        File f = new File(path);
        for (String name : f.list()) {
            System.out.println(name);
        }
    }

    /**
     * 得到当前的文件目录列表
     */
    @Test
    public void getFilelist() {
        File path = new File(".");
        for (File f : path.listFiles()) {
            if (f.isDirectory()) {
                System.out.println("文件夹:" + f.getName());
            } else {
                System.out.println("记事本:" + f.getName());

            }
        }
    }
}


      DirFiter这个类存在的唯一原因就是将accept方法。创建这个类的目的在于把accept0方法提供给listO使用,使list(可以回调accept,进而以决定哪些文件包含在列表中。因此,这种结构也常常称为回调。更具体地说,这是-一个策略模式的例子,因为list(实现了基本的功能,而且按照FilenameFilter的形式提供了这个策略,以便完善listO在提供服务时所需的算法。因为list(接受FilenameFilter对象作为参数,这意味着我们可以传递实现了FilenameFilter接口的任何类的对象,用以选择(甚至在运行时) list方 法的行为方式。策略的目的就是提供了代码行为的灵活性。

      accept方法必须接受-一个代表某个特定文件所在目录的File对象,以及包含了那个文件名的一个String。记住一点: list方法会为此目录对象下的每个文件名调用accept,来判断该文件是否包含在内;判断结果由accept返回的布尔值表示。

      accept会使用一个 正则表达式的matcher对象,来查看此正则表达式regex是否匹配这个文件的名字。通过使用accept, list方法会返回一个数组。

 DirFilter2用了匿名内部类

这个例子很适合用一个匿名内部类进行改写。首先创建一个filter方法,它会返回一个指向FilenameFilter的引用注意,传向flter的参数必须是final的。这在匿名内部类中是必需的,这样它才能够使用来自该类范围之外的对象。这个设计有所改进,因为现在FilenameFilter类 紧密地和DirList2绑定在一起。然而,我们可以进一步修改该方法,定义一个作为list参数的匿名内部类;这样一来程序会变 得更小:比如在上的代码中main方法标注的第三部分中直接使用了匿名内部类,没有对别的对象产生依赖
既然匿名内部类直接使用args[0],那么传递给main方法的参数现在就是final的。
这个例子展示了匿名内部类怎样通过创建特定的、一次性的类来解决问题。此方法的一个优点就是将解决特定问题的代码隔离、聚拢于-一点。而另一方面,这种方法却不易阅读,因此要谨慎使用。

      程序设计中一项常见的任务就是在文件集上执行操作,这些文件要么在本地目录中,要么遍布于整个目录树中。如果有一种工具能够为你产生这个文件集,那么它会非常有用。下面的实用工具类就可以通过使用local0方法产生由本地目录中的文件构成的File对象数组,或者通过使用walk0方法产生给定目录下的由整个目录树中所有文件构成的List<File> (File对象 比文件名更有用,因为File对象包含更多的信息)。这些文件是基于你提供的正则表达式而被选中的:


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

public final class Directory {
    public static File[] local(File f, final String regex) {
        return f.listFiles(new FilenameFilter() {
            private Pattern p = Pattern.compile(regex);

            @Override
            public boolean accept(File dir, String name) {
                // TODO Auto-generated method stub
                return p.matcher(name).matches();
            }
        });
    }

    public static File[] local(String path, final String regex) {
        return local(new File(path), regex);
    }

    public static class TreeInfo implements Iterable<File> {
        public List<File> files = new ArrayList<File>();
        public List<File> dirs = new ArrayList<File>();

        @Override
        public Iterator<File> iterator() {
            // TODO Auto-generated method stub
            return files.iterator();
        }

        void addAll(TreeInfo other) {
            files.addAll(other.files);
            files.addAll(other.dirs);
        }

        public String toString() {
            return "dir: " + PPrint.pFormat(dirs) + "

" + "file: " + PPrint.pFormat(files);
        }
    }

    public static TreeInfo walk(File start, String regex) {
        return recurseDirs(start, regex);
    }

    public static TreeInfo walk(String start, String regex) {
        return recurseDirs(new File(start), regex);
    }

    public static TreeInfo walk(File start) {
        return recurseDirs(start, ".*");
    }

    public static TreeInfo walk(String start) {
        return recurseDirs(new File(start), ".*");
    }

    static TreeInfo recurseDirs(File f, String regex) {
        TreeInfo t = new TreeInfo();
        for (File item : f.listFiles()) {
            if (item.isDirectory()) {
                t.dirs.add(item);
                t.addAll(recurseDirs(item, regex));
            } else {
                if (item.getName().matches(regex))
                    t.files.add(item);
            }
        }
        return t;
    }

    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println(walk("E:\学道\HTML\Commons"));
        } else {
            for (String arg : args) {
                System.out.println(walk(arg));
            }
        }
    }
}


      local0方法使用被称为listFileO的File.list(的变体来产生File数组。可以看到,它还使用了FilenameFilter。如果需要List而不是数组,你可以使用Arrays.asListO自己对结果进行转换。

      walk方法将开始目录的名字转换为File对象,然后调用recurseDirs,该方法将递归地遍历目录,并在每次递归中都收集更多的信息。为了区分普通文件和目录,返回值实际上是一个对象“元组”一个List持有所有普通文件, 另一个持有目录。这里,所有的域都被有意识地设置成了public,因为TreeInfo的使命只是将对象收集起来一-如果你只是返回List, 那么就不需要将其设置为private,因为你只是返回一个对象对,不需要将它们设置为private。注意,TreeInfo实现了Iterable<File>,它将产生文件,使你拥有在文件列表上的“ 默认迭代”,而你可以通过声明“.dirs” 来指定目录。

      TreeInfo.toString方法使用了一个“灵巧打印机”类,以使输出更容易浏览。容器默认的toString方法会在单个行中打印容器中的所有元素,对于大型集合来说,这会变得难以阅读,因此你可能希望使用可替换的格式化机制。下面是一个可以添加新行并缩排所有元素的工具:

import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
 * 加上【】
 * @author 11153
 *
 */
public class PPrint {
    public static String pFormat(Collection<?> con) {
        if(con.size()==0) return "[]";
        StringBuilder result=new StringBuilder("[");
        for(Object e:con) {
            if(con.size()!=1) result.append("
  ");
            result.append(e);
        }
        if(con.size()!=1) {
            result.append("
");
        }
        result.append("]");
        return result.toString();
    }
    public static void pprint(Object[] o) {
        System.out.println(pFormat(Arrays.asList(o)));
    }
    public static void pprint(List<File> dirs) {
        System.out.println(pFormat(dirs));
    }
    public static void main(String[] args) {
        PPrint.pprint(Directory.walk("E:\学道\HTML\编程全解").dirs);
        PPrint.pprint(Directory.walk("E:\学道\HTML\编程全解").files);
    }
}


      pformat方法可以从Collection中产生格式化的String,而pprint0方 法使用pformat0来执行其任务。注意,没有任何元素和只有一个元素这两种特例进行了不同的处理。上面还有一 一个用于数组的pprint版本。
我们可以更进一步,创建一个工具,让他可以在目录中穿行,并且根据Strategy对象那个来处理哲学目录中的文件,这是策略设计模式的另一实例


package File;

import java.io.File;
import java.io.IOException;

public class ProcessFiles {

    public interface Strategy {
        void process(File f);
    }
    private String ext;
    private Strategy s;
    public ProcessFiles(Strategy s,String ext){
        this.s=s;
        this.ext=ext;
    }

    public void start(String[] args) {
        try {
            if (args.length == 0) {
                processDirectoryTree(new File("."));
            } else {
                for (String arg : args) {
                    File f = new File(arg);
                    if (f.isDirectory())
                        processDirectoryTree(f);
                    else {
                        if (!arg.endsWith("." + ext))
                            arg += "." + ext;
                        s.process(new File(arg).getCanonicalFile());
                    }
                }
            }
        } catch (IOException e) {

        }
    }

    public void processDirectoryTree(File root) throws IOException {
        for (File f : Directory.walk(root.getAbsolutePath(), ".*\." + ext))
            s.process(f.getCanonicalFile());
    }

    public static void main(String[] args) {
        new ProcessFiles(new ProcessFiles.Strategy() {
            public void process(File f) {
                System.out.println(f);
            }
        },"java").start(args);;
    }
}


      Strategy接口内嵌在ProcessFiles中,使得如果你希望实现它,就必须实现ProcessFiles.Strategy,它为读者提供了更多的上下文信息。ProcessFiles执行 了查找具有特定扩展名(传递给构造器的ext参数)的文件所需的全部工作,并且当它找到匹配的文件时,将直接把文件传递给Strategy对象(也是传递给构造器的参数)。

      如果你没有提供任何参数,那么ProcessFiles就假设你希望遍历当前目录下的所有目录。你也可以指定特定的文件,带不带扩展名都可以(如果必需的话,它会添加上扩展名),或者指定一个或多个目录。

      在main方法中,你看到了如何使用这个工具的基本示例,它可以根据你提供的命令行来打印所有的Java源代码文件的名字。


 




 
 
原文地址:https://www.cnblogs.com/QianYue111/p/10492330.html