Java IO之文件基础

在日常的工作中文件IO操作是一种非常常用的操作,本篇文章简单的介绍一下基本但很重要的File类和常用方法,以及对目录和文件的操作等等。

1、File类

File(文件)这个名称有一定的误导性,我们通常认为它指代的是文件,实际上却并非如此。它既能代表一个特定文件的名称,又能代表一个目录下的一组文件的名称。如果它指的是一个文件集,我们就可以对此集合调用list()方法,会返回一个字符数组,因为元素的个数是固定的。也许FilePath会更贴切一些。

1.1 目录列表

查看一个目录列表,可以使用两种方法来使用File对象。
1. 获得全部列表,不带参数的list()方法
2. 获得受限列表,使用目录过滤器

请看下列示例代码:

import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.regex.Pattern;

public class DirList {

    public static void main(final String[] args) {
        File path = new File("D:\\DirTest");
                String[] list;

        if (args.length == 0)
            list = path.list();
        else
            list = path.list(new FilenameFilter() {
                private Pattern pattern = Pattern.compile(args[0]);

                @Override
                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);
        }
    }
}

此程序非常简单,列出目标文件夹下面的文件(文件夹名和文件名)。

特别注意,windows目录下路径分隔符为\\。

args[0]是什么呢?这是我们运行在命令行用java命令执行代码时输入的参数,这里我们将其作为正则表达式输入,当然在IDE(此处为Eclipse)中也是可以输入此参数的(点击菜单栏Run->Run Configurations),见下图。我们完全可以在程序中定义一个String来完成同样的操作,这里不需要纠结细节。
String[] args参数

上面的代码中主要用到了
- FilenameFilter接口

它其中只有一个accept方法,目的在于使list()可以回调accept(),进而决定哪些文件包含在列表中。

即:list()方法会为此目录对象下的每个文件名调用accept(),来判断该文件是否包含在内。

这是一个策略模式的典型例子,list()实现了基本的功能,而且按照FilenameFilter的形式提供了这个策略,以便完善list()在提供服务时所需的算法。

  • Pattern (final Class)

此类用于正则表达式的编译表示形式。指定为字符串的正则表达式必须首先被编译为此类的实例。然后,可将得到的模式用于创建Matcher对象,依照正则表达式,该对象可以与任意字符序列匹配。
常用方式如下:

 Pattern p = Pattern.compile("a*b"); 
 Matcher m = p.matcher("aaaaab");
 boolean b = m.matches();

示例中a*b代表正则表达式,当然我们可以将其换为其它的正则表达式。关于正则表达式的详细用法,请查看其它文档,这里不做过多介绍。

例如在上面的code中,我们可以使用”M.*.java”来输出以M开头的java文件。关于更详细的类使用和介绍,请参看官方文档。

1.2 file的创建及检查

通过file类的常用方法我们可以完成一些对文件/文件夹的常用查询操作,见如下代码:

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MakeDir {

    private static void usage() {
        System.out.println();
    }

    private static void fileData(File f) {
        System.out.println("abs path:" + f.getAbsolutePath() + "\n Can read :"
                + f.canRead() + "\n Can write :" + f.canWrite()
                + "\n get name :" + f.getName() + "\n get parent :"
                + f.getParent() + "\n get path :" + f.getPath() + "\n length :"
                + f.length() + "\n lastModified :" + f.lastModified());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date = sdf.format(new Date(f.lastModified()));

        System.out.println("lastModified for read " + date);
        if (f.isFile()) {
            System.out.println("f is a file ");
        } else if (f.isDirectory()) {
            System.out.println("f is a directory ");
        }
    }

    public static void main(String[] args) {
        File file = new File("D:\\DirTest");
        if (file.exists()) {
            System.out.println(file + "   exists\n");
        } else {
            file.mkdirs();
            System.out.println(file + "   created\n");
        }
        fileData(file);
    }

}

输出如下:

D:\DirTest   exists

abs path:D:\DirTest
 Can read :true
 Can write :true
 get name :DirTest
 get parent :D:\
 get path :D:\DirTest
 length :4096
 lastModified :1480425237915
lastModified for read 2016-11-29 21:13:57
f is a directory 

我们随便输入一个不存在的文件夹,结果如下:

D:\DirTest2   created

abs path:D:\DirTest2
 Can read :true
 Can write :true
 get name :DirTest2
 get parent :D:\
 get path :D:\DirTest2
 length :0
 lastModified :1480427281934
lastModified for read 2016-11-29 21:48:01
f is a directory 

可见它实现了我们想要的功能,在此基础上我们可以添加更高级的功能,比如删除某一个时间点后产生的文件,重命名文件等等。

1.3 循环获取目录下的特定文件

有了上面的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 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();
            }
        });
    }

    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>();

        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);
        }
    }

    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), ".*");
    }

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

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

}

很容易发现,上面只是循环遍历给定的目录,并将其分别加入到两个列表中,然后输出到控制台。虽然实例很简单但是我们稍加扩展便可以实现其他的功能。

在本篇中我们用到了正则表达式的一些知识,但是并没有对其作深入的了解,仅仅使用了一些基础的用法。鉴于其在日常使用中应用广泛功能强大,所以在下一篇中我将会分享一些使用正则表达式的心得。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值