java温故而知新之File操作

本文提供两个Java文件操作实例,包括目录文件过滤器和目录遍历工具类,展示了如何使用File类及FilenameFilter接口进行文件过滤与目录遍历。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


本文中例举了关于file操作的几个实例,包括DirList.java(显示目录下文件),Directory(显示当前目录或遍历目录结构的工具类)以及使用Directory的例子ProcessFile。

这些例子同步更新于我的github上:https://github.com/lovekun/JavaDemo 的JavaFile文件中


先来看第一个例子,关于File类的。

package file;

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

/*
 * 该程序实现目录过滤器的功能
 * 根据参数显示指定目录下所有文件
 */

public class DirList {

	public static void main(String[] args) {
		File path = new File("./src/file");
		String[] list;
		if(args.length == 0){
			list = path.list();
		}else{
			//list回调DirFilter中的accept方法。
			list = path.list(new DirFilter(args[0]));
		}
		//调用Arrays.sort的静态方法来对list中的String进行排序
		Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
		for(String dirItem : list)
			System.out.println(dirItem);
	}
	
}

class DirFilter implements FilenameFilter{
	private Pattern pattern;
	
	public DirFilter(String regex) {
		pattern = Pattern.compile(regex);
	}

	@Override
	public boolean accept(File dir, String name) {
		
		return pattern.matcher(name).matches();
	}
	
}


File类的含义和Linux/Unix思想相似,目录也被看成是一种文件,java中对文件和目录也是这样处理的,File既能代表一个特定文件的名称,又能代表一个目录下的一组文件的名称。

java的API文档中对File类的描述:http://docs.oracle.com/javase/7/docs/api/

这个例子展示的功能就是一个目录列表过滤器。DirFilter类继承了FilenameFilter接口,使list方法能够回调accept方法。

回调过程看下File类下的list方法源码:

    /**
     * Returns an array of strings naming the files and directories in the
     * directory denoted by this abstract pathname that satisfy the specified
     * filter.  The behavior of this method is the same as that of the
     * <code>{@link #list()}</code> method, except that the strings in the
     * returned array must satisfy the filter.  If the given
     * <code>filter</code> is <code>null</code> then all names are accepted.
     * Otherwise, a name satisfies the filter if and only if the value
     * <code>true</code> results when the <code>{@link
     * FilenameFilter#accept}</code> method of the filter is invoked on this
     * abstract pathname and the name of a file or directory in the directory
     * that it denotes.
     *
     * @param  filter  A filename filter
     *
     * @return  An array of strings naming the files and directories in the
     *          directory denoted by this abstract pathname that were accepted
     *          by the given <code>filter</code>.  The array will be empty if
     *          the directory is empty or if no names were accepted by the
     *          filter.  Returns <code>null</code> if this abstract pathname
     *          does not denote a directory, or if an I/O error occurs.
     *
     * @throws  SecurityException
     *          If a security manager exists and its <code>{@link
     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
     *          method denies read access to the directory
     */
    public String[] list(FilenameFilter filter) {
	String names[] = list();
	if ((names == null) || (filter == null)) {
	    return names;
	}
	ArrayList v = new ArrayList();
	for (int i = 0 ; i < names.length ; i++) {
	    if (filter.accept(this, names[i])) {
		v.add(names[i]);
	    }
	}
	return (String[])(v.toArray(new String[v.size()]));
    }

String names[] = list()调用了无参数的list()方法,把当前目录下所有文件的名字赋值给字符串数组names,然后判断如果names为空或者过滤内容(filter)为空,则返回该目录下所有文件。否则,便利目录下的所有文件,并为每个文件调用filter的accept方法,符合条件就把文件名加入到ArrayList中,并最终返回字符串数组。

再来看看FilenameFilter接口:

package java.io;

/**
 * Instances of classes that implement this interface are used to
 * filter filenames. These instances are used to filter directory
 * listings in the <code>list</code> method of class
 * <code>File</code>, and by the Abstract Window Toolkit's file
 * dialog component.
 *
 * @author  Arthur van Hoff
 * @author  Jonathan Payne
 * @version %I%, %G%
 * @see     java.awt.FileDialog#setFilenameFilter(java.io.FilenameFilter)
 * @see     java.io.File
 * @see     java.io.File#list(java.io.FilenameFilter)
 * @since   JDK1.0
 */
public
interface FilenameFilter {
    /**
     * Tests if a specified file should be included in a file list.
     *
     * @param   dir    the directory in which the file was found.
     * @param   name   the name of the file.
     * @return  <code>true</code> if and only if the name should be
     * included in the file list; <code>false</code> otherwise.
     */
    boolean accept(File dir, String name);
}

该接口只有一个方法accept来判断指定的文件能否被包含在file list中。

总结下上面的小例子:通过运行是传入的参数来对指定目录下的文件进行过滤输出。当然,你也可以把上面的DirFilter类写成内部类(具体可以参看《java编程思想》第18章Java IO系统)。这个例子比较难理解的感觉应该就在path.list(FilenameFilter)对accept()方法的回调。


直接来看第二个例子:也算是一个实用工具,可以在平时写代码时碰到关于目录遍历相关的内容时,直接拿过来用。

直接上代码:

package 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;
/*
 * ProcessFiles是一个目录工具类。
 * 该代码实现的功能:
 * 1、local()方法产生本地目录中的文件构成的File对象数组,
 * 	  有两个不同参数的local()方法,一个传File,一个传String
 * 2、walk()方法产生给定目录下的由整个目录树所有文件构成的List<File>。
 * 
 */
public class Directory {
	
	//listFiles下采用匿名内部类的结构
	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();
			}
		});
	}
	
	//重载local方法
	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() {
			return files.iterator();
		}
		
		void addAll(TreeInfo other){
			files.addAll(other.files);
			dirs.addAll(other.dirs);
		}
		//toString()方法是会自动调用的
		//默认容器的toString会在一行把容器里所有元素全部打印
		//所以这里重写了toString方法
		public String toString(){
			return "dirs: " + PPrint.pformat(dirs) + "\n\nfiles: " + PPrint.pformat(files);
		}
	}
	
	/*
	 * 重载了四种walk()方法
	 */
	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){
			//这里输出字符串,会自动调用TreeInfo的toString方法
			System.out.println(walk("."));
		}else{
			for(String arg : args){
				System.out.println(walk(arg));
			}
		}
	}

}

代码细节,注释已经写的比较清楚了,两个主要的方法local()和walk().

local()方法实质上就是上一个例子的实用内部类的另一种写法,walk()方法会在指定目录下对该目录下所有文件进行遍历。


看看如何使用上面的工具类:

package file;

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

/*
 * 根据提供的需要过滤的扩展名ext来输出当前
 * 目录先所有符合条件的文件(不传入参数的时候)
 */
public class ProcessFiles {
	
	public interface Strategy{
		void process(File file);
	}
	
	private Strategy strategy;
	private String ext;
	
	//构造方法传入两个参数接口Strategy和需要过滤的文件扩展名
	public ProcessFiles(Strategy strategy, String ext) {
		this.strategy = strategy;
		this.ext = ext;
	}

	public void start(String[] args){
		try{
			if(args.length == 0){
				processDirectoryTree(new File("."));
			}else{
				for(String arg : args){
					if(arg.endsWith("." + ext))
						arg += "." + ext;
					strategy.process(new File(arg).getCanonicalFile());
				}
			}
		}catch(IOException e){
			throw new RuntimeException(e);
		}
	}
	
	public void processDirectoryTree(File root) throws IOException{
		for(File file : Directory.walk(root.getAbsolutePath(), ".*\\." + ext))
			strategy.process(file.getCanonicalFile());
	}

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

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值