虽然Google的guava对Java的IO操作进行了一定封装,但是它更偏向于集合、并发和缓存,在实际项目中,我非常喜欢guava,同时我也非常喜欢Apache的一个工具包org.apache.commons.io,这两个工具包提供非常强大的工具能力,能够简化代码逻辑,提高开发效率和质量,是每个Java程序员都应该掌握的工具包。此文简单介绍一下org.apache.commons.io,详细的可参考其API注,此文绝大部分内容翻译自http://www.javacodegeeks.com/2014/10/apache-commons-io-tutorial.html,感兴趣的查看原文,本文源码请移步
Apache Commons IO是Apache开源的一个工具包,其封装了对IO的常见操作,使开发人员只需要少量的代码就能完成大量的IO操作,此文主要介绍如下几个工具类
- Utility classes
- Input
- Output
- Filters
- Comparators
- File Monitor
目前org.apache.commons.io2.4版本并未托管到Maven库,所以需要自行下载然后将下载的commons-io-2.4.jar添加到环境变量中
1、Utils(FileUtils,FilenameUtils,FileSystemUtils)这三个类主要提供了对文件、文件名及文件系统的操作,API非常简单,通过API名称都能知道其作用,
示例如下
//文件绝对路径 private static final String EXAMPLE_TXT_PATH = "/Users/fly/work/GitHub/algorithm/src/main/java/com/fly/practice/apachecommonsio/commonio.txt"; //文件父目录 private static final String PARENT_DIR = "/Users/fly/work/GitHub/algorithm/src/main/java/com/fly/practice/apachecommonsio"; public static void runExample() throws IOException { System.out.println("Utility Classes example..."); // FilenameUtils类示例 //获取完整路径 System.out.println("Full path of exampleTxt: " + FilenameUtils.getFullPath(EXAMPLE_TXT_PATH)); //获取名称 System.out.println("Full name of exampleTxt: " + FilenameUtils.getName(EXAMPLE_TXT_PATH)); //获取扩展名 System.out.println("Extension of exampleTxt: " + FilenameUtils.getExtension(EXAMPLE_TXT_PATH)); System.out.println("Base name of exampleTxt: " + FilenameUtils.getBaseName(EXAMPLE_TXT_PATH)); // FileUtils类示例 // 通过FileUtils.getFile(String)创建File对象,然后根据FileUtils.lineIterator(File) //获取行迭代器 File exampleFile = FileUtils.getFile(EXAMPLE_TXT_PATH); LineIterator iter = FileUtils.lineIterator(exampleFile); System.out.println("Contents of exampleTxt..."); while (iter.hasNext()) { System.out.println("\t" + iter.next()); } iter.close(); // 目录是否已经包含文件 File parent = FileUtils.getFile(PARENT_DIR); System.out.println("Parent directory contains exampleTxt file: " + FileUtils.directoryContains(parent, exampleFile)); // IOCase类示例 String str1 = "This is a new String."; String str2 = "This is another new String, yes!"; System.out.println("Ends with string (case sensitive): " + IOCase.SENSITIVE.checkEndsWith(str1, "string.")); System.out.println("Ends with string (case insensitive): " + IOCase.INSENSITIVE.checkEndsWith(str1, "string.")); System.out.println("String equality: " + IOCase.SENSITIVE.checkEquals(str1, str2)); // FileSystemUtils类示例 System.out.println("Free disk space (in KB): " + FileSystemUtils.freeSpaceKb("/Users")); System.out.println("Free disk space (in MB): " + FileSystemUtils.freeSpaceKb("/Users") / 1024); }
2、InputStream,其提供了XmlStreamReader工具类,能够获取xml的文件编码等操作,
示例如下
private static final String XML_PATH = "/Users/fly/work/GitHub/algorithm/src/main/java/com/fly/practice/apachecommonsio/test.xml"; public static void runExample() { System.out.println("Input example..."); XmlStreamReader xmlReader = null; try { // XmlStreamReader:读取一个xml文件,提供了过去文件编码API File xml = FileUtils.getFile(XML_PATH); xmlReader = new XmlStreamReader(xml); System.out.println("XML encoding: " + xmlReader.getEncoding()); } catch (IOException e) { e.printStackTrace(); } finally { try { xmlReader.close(); } catch (IOException e) { e.printStackTrace(); } } }
3、Output,其提供的TeeInputStream,TeeOutputStream类能将输入流快速拷贝到输出流中
private static final String INPUT = "This should go to the output."; public static void runExample() { System.out.println("Output example..."); TeeInputStream tee=null; TeeInputStream teeIn = null; TeeOutputStream teeOut = null; try { //TeeInputStream能将输入流快速拷贝到输出流中 ByteArrayInputStream in = new ByteArrayInputStream(INPUT.getBytes("US-ASCII")); ByteArrayOutputStream out = new ByteArrayOutputStream(); tee = new TeeInputStream(in, out, true); tee.read(new byte[INPUT.length()]); System.out.println("Output stream: " + out.toString()); //能将输入流同时拷贝到两个输出流 ByteArrayOutputStream out1 = new ByteArrayOutputStream(); ByteArrayOutputStream out2 = new ByteArrayOutputStream(); teeOut = new TeeOutputStream(out1, out2); teeIn = new TeeInputStream(in, teeOut, true); teeIn.read(new byte[INPUT.length()]); System.out.println("Output stream 1: " + out1.toString()); System.out.println("Output stream 2: " + out2.toString()); } catch (IOException e) { e.printStackTrace(); } finally { //此处不需要关闭teeOut,当关闭teeIn时,同时会关闭teeOut try { teeIn.close(); tee.close();} catch (IOException e) { e.printStackTrace(); } } }
4、Filters,commons-io提供了多种过滤器,能够根据条件过滤指定目录下的文件,同时还支持过滤器组合,
示例如下
private static final String PARENT_DIR = "/Users/fly/work/GitHub/algorithm/src/main/java/com/fly/practice/apachecommonsio"; public static void runExample() { System.out.println("File Filter example..."); // NameFileFilter:获取指定目录下,符合给定文件列表的文件 //例如获取此例,获取PARENT_DIR目录下commonios和commonio.txt文件 File dir = FileUtils.getFile(PARENT_DIR); String[] acceptedNames = {"commonios", "commonio.txt"}; for (String file: dir.list(new NameFileFilter(acceptedNames, IOCase.INSENSITIVE))) { System.out.println("File found, named: " + file); } //WildcardFileFilter:支持正则匹配,获取指定目录下,满足正则的文件 for (String file: dir.list(new WildcardFileFilter("*common*"))) { System.out.println("Wildcard file found, named: " + file); } // PrefixFileFilter:获取以给定字符串为前缀的文件名 for (String file: dir.list(new PrefixFileFilter("common"))) { System.out.println("Prefix file found, named: " + file); } // SuffixFileFilter::获取以给定字符串为后缀的文件名 for (String file: dir.list(new SuffixFileFilter(".txt"))) { System.out.println("Suffix file found, named: " + file); } // OrFileFilter:支持传入多个过滤器,过滤器之间是或的关系 for (String file: dir.list(new OrFileFilter( new WildcardFileFilter("*ample*"), new SuffixFileFilter(".txt")))) { System.out.println("Or file found, named: " + file); } //AndFileFilter:支持传入多个过滤器,过滤器之间是且的关系 for (String file: dir.list(new AndFileFilter( new WildcardFileFilter("*ample*"), new NotFileFilter(new SuffixFileFilter(".txt"))))) { System.out.println("And/Not file found, named: " + file); } }
5、Comparators,commons-io提供了多种文件比较工具类,能够根据文件名称、文件大小、修改时间等对目录下的文件进行排序,
简单示例如下
private static final String PARENT_DIR = "/Users/fly/work/GitHub/algorithm/src/main/java/com/fly/practice/apachecommonsio"; private static final String FILE_1 = "/Users/fly/work/GitHub/algorithm/src/main/java/com/fly/practice/apachecommonsio/commonio.txt"; private static final String FILE_2 = "/Users/fly/work/GitHub/algorithm/src/main/java/com/fly/practice/apachecommonsio/test.xml"; public static void runExample() { System.out.println("Comparator example..."); //NameFileComparator:根据文件名称排序,IOCase表示是否大小写敏感 File parentDir = FileUtils.getFile(PARENT_DIR); NameFileComparator comparator = new NameFileComparator(IOCase.SENSITIVE); File[] sortedFiles = comparator.sort(parentDir.listFiles()); System.out.println("Sorted by name files in parent directory: "); for (File file: sortedFiles) { System.out.println("\t"+ file.getAbsolutePath()); } // SizeFileComparator:根据文件大小排序,小文件在前,其构造器支持传一个boolean类型的参数, //true表示需要计算该目录下的目录大小 //flase表示不需要计算该目录下的目录大小(0) SizeFileComparator sizeComparator = new SizeFileComparator(true); File[] sizeFiles = sizeComparator.sort(parentDir.listFiles()); System.out.println("Sorted by size files in parent directory: "); for (File file: sizeFiles) { System.out.println("\t"+ file.getName() + " with size (kb): " + file.length()); } // LastModifiedFileComparator:根据修改时间排序,最新修改排前 LastModifiedFileComparator lastModified = new LastModifiedFileComparator(); File[] lastModifiedFiles = lastModified.sort(parentDir.listFiles()); System.out.println("Sorted by last modified files in parent directory: "); for (File file: lastModifiedFiles) { Date modified = new Date(file.lastModified()); System.out.println("\t"+ file.getName() + " last modified on: " + modified); } }
6、File Monitor,commons-io还提供了对目录的监控类,可以对指定目录进行监控,如果目录下文件发生变化(修改,增加,删除等),其监控会向监听器发送相应的事件。
示例如下
private static final String EXAMPLE_PATH = "/Users/fly/work/GitHub/algorithm/src/main/java/com/fly/practice/apachecommonsio/commonio.txt"; private static final String PARENT_DIR = "/Users/fly/work/GitHub/algorithm/src/main/java/com/fly/practice/apachecommonsio"; private static final String NEW_DIR = "/Users/fly/work/GitHub/algorithm/src/main/java/com/fly/practice/apachecommonsio/newDir"; private static final String NEW_FILE = "/Users/fly/work/GitHub/algorithm/src/main/java/com/fly/practice/apachecommonsio/newFile.txt"; public static void runExample() { System.out.println("File Monitor example..."); // FileEntry // We can monitor changes and get information about files // using the methods of this class. FileEntry entry = new FileEntry(FileUtils.getFile(EXAMPLE_PATH)); System.out.println("File monitored: " + entry.getFile()); System.out.println("File name: " + entry.getName()); System.out.println("Is the file a directory?: " + entry.isDirectory()); // 文件(目录)监控 // 给指定目录创建观察者,并添加监听器,对事件作出响应 File parentDir = FileUtils.getFile(PARENT_DIR); FileAlterationObserver observer = new FileAlterationObserver(parentDir); observer.addListener(new FileAlterationListenerAdaptor() { @Override public void onFileCreate(File file) { System.out.println("File created: " + file.getName()); } @Override public void onFileDelete(File file) { System.out.println("File deleted: " + file.getName()); } @Override public void onDirectoryCreate(File dir) { System.out.println("Directory created: " + dir.getName()); } @Override public void onDirectoryDelete(File dir) { System.out.println("Directory deleted: " + dir.getName()); } }); // 创建一个每隔500毫秒就做一次检查的监控 FileAlterationMonitor monitor = new FileAlterationMonitor(500, observer); try { monitor.start(); //启动监控后,对监控目录做一些文件操作,触发监听器 File newDir = new File(NEW_DIR); File newFile = new File(NEW_FILE); newDir.mkdirs(); newFile.createNewFile(); Thread.sleep(1000); FileDeleteStrategy.NORMAL.delete(newDir); FileDeleteStrategy.NORMAL.delete(newFile); Thread.sleep(1000); monitor.stop(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } }
以上只是对commons-io的一个简单介绍,从中可以看出该工具包提供了强大的IO操作,更多功能还需实际项目中不断探索