Java IO File 文件管理 Java编程思想读书笔记

来源:互联网 发布:简述java垃圾回收机制 编辑:程序博客网 时间:2024/05/21 11:24

可以使用File管理磁盘上的文件。

File对象最简单的构造器接受一个完全的文件。如果没有提供路径名,则使用当前路径。

File f = new File("test.txt");

注意:考虑到可移植问题,可以使用File.separator得到当前 运行平台所使用的文件分隔符,在Windows环境中,它是反斜线(\),在UNIX环境中,它是斜线(/)。

如果File指定文件不存在。可以调用File类的createNewFile方法,createNewFile方法只有在具有指定的文件不存在时才会创建文件,并且返回boolean值说明文件是否创建成功。

可以调用File对象的exist方法查询指定的文件是否存在。

File对象既可以表示文件,也可以表示目录。可以使用isDirectory和isFile方法来了解一个文件对象表示的是文件还是目录。

让一个对象表示目录,只需在File构造器提供目录名:

File tempDir = new File(File.separator+"temp");

如果指定目录不存在,可以使用mkdir方法创建它:

tempDir .mkdir();

如果指定目录的父目录都不存在,可以使用mkdirs方法创建它:

tempDir .mkdirs();

如果一个文件对象表示的是目录,使用list()方法可以获得由这个目录的文件名构成的字符串数组。

如果我们想取得不同的目录列表,只需要再创建一个不同的File对象就可以了。

提示:在处理文件或目录名时,应该总是使用File对象而不是字符串。这样做的好处很多,如,File类的equals方法知道某些文件系统是不是大小写敏感的,而不是自己判断。



目录列表器

如果你想查看一个目录列表,可以调用不带参数的list()方法,便获得此File对象包含的全部列表。然而,如果想获得一个受限列表,如想得到所有扩展名为.java的文件,那么我们就是用到“目录过滤器”(FilenameFilter)。

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

package ioStudy;import java.io.*;import java.util.Arrays;import java.util.regex.Pattern;//定义一个文件过滤器,根据正则表达式过滤文件class DirFilter implements FilenameFilter{private Pattern pattern;public DirFilter(String regex){pattern = Pattern.compile(regex);}public boolean accept(File dir, String name){return pattern.matcher(name).matches();}}public class DirList {public static void main(String[] args) {File path = new File("src/ioStudy");//当前java文件所在目录String[] list;list = path.list(new DirFilter("\\w+\\.java"));//查看所有的java文件Arrays.sort(list,String.CASE_INSENSITIVE_ORDER);for(String dirItem : list) {System.out.println(dirItem);}}}

这里DirFilter类实现了FilenameFilter接口,注意FilenameFilter接口非常简单:

public interface FilenameFilter {boolean accept(File dir, String name);}

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

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

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


上面例子可以通过一个匿名内部类实现:

package ioStudy;import java.io.*;import java.io.FilenameFilter;import java.util.Arrays;import java.util.regex.Pattern;public class DirList3 {public static void main(String[] args) {File path = new File("src/ioStudy");//当前java文件所在目录String[] list;list = path.list(new FilenameFilter() {private Pattern pattern = Pattern.compile("\\w+\\.java");//查看所有的java文件public boolean accept(File dir, String name) {return pattern.matcher(name).matches();}});Arrays.sort(list,String.CASE_INSENSITIVE_ORDER);for(String dirItem : list) {System.out.println(dirItem);}}}

此方法的一个优点就是将解决特定问题的代码隔离,聚拢于一点。而另一方面,这种方法不易阅读,因此要谨慎使用。


目录实用工具

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

    import java.io.*;    import java.util.*;    import java.util.regex.Pattern;    public class Directory {    /**     * @param dir 目录File     * @param regex过滤正则表达式     * @return传递目的目录File和过滤正则表达式,返回目的目录下根据正则表达式过滤后的File数组     */    public static File[] local(File dir, final String regex) {    return dir.listFiles(new FilenameFilter() {    private Pattern pattern = Pattern.compile(regex);    public boolean accept(File dir, String name) {    return pattern.matcher(new File(name).getName()).matches();    }    });    }        /**     * 传递目的目录字符串和过滤正则表达式,返回目的目录下根据正则表达式过滤后的File数组     */    public static File[] local(String path, final String regex) {    return local(new File(path), regex);    }            //TreeInfo提供了文件迭代器和添加一个TreeInfo的方法    public static class TreeInfo implements Iterable<File> {    public List<File> files = new ArrayList<File>();    public List<File> dirs = new ArrayList<File>();        public Iterator<File> iterator(){    return files.iterator();    }    void addAll(TreeInfo other){    files.addAll(other.files);    dirs.addAll(other.dirs);    }    public String toString() {    return "dirs: " + PPrint.pformat(dirs) +     "\n\nfiles: " + PPrint.pformat(files);    }    }        /**     * @param startDir目的目录File     * @param regex过滤正则表达式     * @return  传递目的目录File和过滤正则表达式,返回目的目录下根据正则表达式过滤后构成的TreeInfo对象     */    private static TreeInfo recurseDirs(File startDir, String regex) {    TreeInfo result = new TreeInfo();    for(File item : startDir.listFiles()) {    if(item.isDirectory()) {    result.dirs.add(item);    } else if(item.getName().matches(regex)) {    result.files.add(item);    }    }    return result;    }        //提供接口    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, ".*");//everythig    }    public static TreeInfo walk(String start) {    return recurseDirs(new File(start), ".*");    }        public static void main(String[] args) {    System.out.println(walk("."));    }    }

local()方法使用了listFile()产生File数组。如果需要List而不是数组,可以使用Arrays.asList()对结果进行转换。

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

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

import java.util.*;public class PPrint {public static String pformat(Collection<?> c) {if(c.size() == 0)return "[]";StringBuilder result = new StringBuilder("[");for(Object elem : c) {if(c.size() != 1)result.append("\n   ");result.append(elem);}if(c.size() != 1)result.append("\n");result.append("]");return result.toString();}public static void pprint(Collection<?> c) {System.out.println(pformat(c));}public static void pprint(Object[] c) {System.out.println(pformat(Arrays.asList(c)));}}

pformat()方法可以从Collection中产生格式化的String,而pprint()方法使用pformat()来执行其任务。注意,没有任何元素和只有一个元素这两种特例进行了不同的处理。


我们更进一步,创建一个工具,它可以在目录中穿行,并且根据Strategy对象来处理这些目录中的文件(这是策略设计模式的另一个示例):

package ioStudy;    import java.io.*;    public class ProcessFiles {    //策略接口    public interface Strategy {    void process(File file);    }    private Strategy strategy;    private String ext;//只处理以ext结尾的文件    public ProcessFiles(Strategy strategy, String ext){    this.strategy = strategy;    this.ext = ext;    }        /**     * 处理rootFile所在目录的所有文件     */    public void processDirectoryTree(File root) throws IOException {    for(File file : Directory.walk(root.getAbsoluteFile(), ".*\\." + ext)){    strategy.process(file.getCanonicalFile());    }    }        /**     * 将数组参数fileNames转化为File数组,并使用strategy处理所有的File     */    public void start(String[] fileNames) {    try {    if(fileNames.length == 0)    processDirectoryTree(new File("."));    else     for(String fileName :fileNames) {    File file = new File(fileName);    if(file.isDirectory())    processDirectoryTree(file);    else {    if(!fileName.endsWith("." + ext))    fileName += "." + ext;    strategy.process(new File(fileName).getCanonicalFile());    }    }    } catch(IOException e) {    throw new RuntimeException(e);    }    }            public static void main(String[] args) {    new ProcessFiles(new ProcessFiles.Strategy() {    public void process(File file) {    System.out.println(file);    }    }, "java").start(new String[]{".", "src/ioStudy"});    }    }

Strategy接口内嵌在ProcessFiles中,使得如果你希望实现它,就必须实现ProcessFiles.Strategy,它为读者提供了更多的上下文信息。ProcessFiles执行了查找具有特定扩展名(传递给构造器的ext参数)的文件所需的全部工作,并且当它找到匹配的文件时,将直接把文件传递给Strategy对象(也是传递给构造器的参数)。
如果你没有提供任何参数,那么ProcessFiles就假设你希望遍历当前目录下的所有目录,你也可以指定特定的文件,带不带扩展名都可以(如果必需的话,它会添加扩展名),或者指定一个或多个目录。


0 0
原创粉丝点击