文章内容
Apache Commons IO是对java.io的扩展,主要是对Java中的bio封装了一些好用的工具类,nio涉及的较少。
Commons IO目前最新版本是2.10.0,最低要求Java8以上。

包结构如下:
1 2 3 4 5 6 7 8 9 | org.apache.commons.io org.apache.commons.io.comparator org.apache.commons.io.file org.apache.commons.io.filefilter org.apache.commons.io.function org.apache.commons.io.input org.apache.commons.io.monitor org.apache.commons.io.output org.apache.commons.io.serialization |
一、IOUtils
IOUtils是Commons IO中最常用的模块。
1、关闭流
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 | nputStream inputStream = new FileInputStream( "test.txt" ); OutputStream outputStream = new FileOutputStream( "test.txt" ); // 原生写法 if (inputStream != null ) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (outputStream != null ) { try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } // commons写法(可以传任意数量的流) IOUtils.closeQuietly(inputStream, outputStream); |
2、读取流
- 输入流转换为byte数组
01 02 03 04 05 06 07 08 09 10 11 12 | // ==== 输入流转换为byte数组 ==== // 原生写法 InputStream is = new FileInputStream( "foo.txt" ); byte [] buf = new byte [ 1024 ]; int len; ByteArrayOutputStream out = new ByteArrayOutputStream(); while ((len = is.read(buf)) != - 1 ) { out.write(buf, 0 , len); } byte [] result = out.toByteArray(); // commons写法 byte [] result2 = IOUtils.toByteArray(is); |
- 输入流转换为字符串
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | // ==== 输入流转换为字符串 ==== // 原生写法 InputStream is = new FileInputStream( "foo.txt" ); BufferedReader br = new BufferedReader( new InputStreamReader(is, "UTF-8" )); StringBuilder sb = new StringBuilder(); String line; while ((line = br.readLine()) != null ) { sb.append(line); } String result = sb.toString(); // commons写法 String result2 = IOUtils.toString(is, "UTF-8" ); // IOUtils.toString 还有很多重载方法 // 将reader转换为字符串 String toString(Reader reader, String charset) throws IOException; // 将url转换为字符串,也就是可以直接将网络上的内容下载为字符串 String toString(URL url, String charset) throws IOException; |
3、其他
- 按照行读取结果
1 2 3 | // 按照行读取结果 InputStream is = new FileInputStream( "test.txt" ); List<String> lines = IOUtils.readLines(is, "UTF-8" ); |
- 将行集合写入输出流
1 2 3 | // 将行集合写入输出流 OutputStream os = new FileOutputStream( "newTest.txt" ); IOUtils.writeLines(lines, System.lineSeparator(), os, "UTF-8" ); |
- 拷贝输入流到输出流
1 2 3 4 | // 拷贝输入流到输出流 InputStream inputStream = new FileInputStream( "src.txt" ); OutputStream outputStream = new FileOutputStream( "dest.txt" ); IOUtils.copy(inputStream, outputStream); |
二、文件相关
文件相关主要有:
- FileUtils:文件工具类
- FilenameUtils:文件名工具类
- PathUtils:路径工具类(主要是操作JDK7新增的java.nio.file.Path类)
1、文件读写
- 读取文件
1 2 3 4 5 6 7 | File readFile = new File( "test.txt" ); // 读取文件 String str = FileUtils.readFileToString(readFile, "UTF-8" ); // 读取文件为字节数组 byte [] bytes = FileUtils.readFileToByteArray(readFile); // 按行读取文件 List<String> lines = FileUtils.readLines(readFile, "UTF-8" ); |
- 写入文件
1 2 3 4 5 6 7 | File writeFile = new File( "out.txt" ); // 将字符串写入文件 FileUtils.writeStringToFile(writeFile, "测试文本" , "UTF-8" ); // 将字节数组写入文件 FileUtils.writeByteArrayToFile(writeFile, bytes); // 将字符串列表一行一行写入文件 FileUtils.writeLines(writeFile, lines, "UTF-8" ); |
2、移动和复制
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 | File srcFile = new File( "src.txt" ); File destFile = new File( "dest.txt" ); File srcDir = new File( "/srcDir" ); File destDir = new File( "/destDir" ); // 移动/拷贝文件 FileUtils.moveFile(srcFile, destFile); FileUtils.copyFile(srcFile, destFile); // 移动/拷贝文件到目录 FileUtils.moveFileToDirectory(srcFile, destDir, true ); FileUtils.copyFileToDirectory(srcFile, destDir); // 移动/拷贝目录 FileUtils.moveDirectory(srcDir, destDir); FileUtils.copyDirectory(srcDir, destDir); // 拷贝网络资源到文件 // 拷贝流到文件 FileUtils.copyInputStreamToFile( new FileInputStream( "test.txt" ), destFile); |
3、其他文件操作
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | File file = new File( "test.txt" ); File dir = new File( "/test" ); // 删除文件 FileUtils.delete(file); // 删除目录 FileUtils.deleteDirectory(dir); // 文件大小,如果是目录则递归计算总大小 long s = FileUtils.sizeOf(file); // 则递归计算目录总大小,参数不是目录会抛出异常 long sd = FileUtils.sizeOfDirectory(dir); // 递归获取目录下的所有文件 Collection<File> files = FileUtils.listFiles(dir, null , true ); // 获取jvm中的io临时目录 FileUtils.getTempDirectory(); |
4、文件名称相关
- 获取名称,后缀等
1 2 3 4 5 6 | // 获取名称,后缀等 String name = "/home/xxx/test.txt" ; FilenameUtils.getName(name); // "test.txt" FilenameUtils.getBaseName(name); // "test" FilenameUtils.getExtension(name); // "txt" FilenameUtils.getPath(name); // "/home/xxx/" |
- 将相对路径转换为绝对路径
1 2 | // 将相对路径转换为绝对路径 FilenameUtils.normalize( "/foo/bar/.." ); // "/foo" |
5、JDK7的Path操作
path既可以表示目录也可以表示文件
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | // 获取当前路径 Path path = PathUtils.current(); // 删除path PathUtils.delete(path); // 路径或文件是否为空 PathUtils.isEmpty(path); // 设置只读 PathUtils.setReadOnly(path, true ); // 复制 PathUtils.copyFileToDirectory(Paths.get( "test.txt" ), path); PathUtils.copyDirectory(Paths.get( "/srcPath" ), Paths.get( "/destPath" )); // 统计目录内文件数量 Counters.PathCounters counters = PathUtils.countDirectory(path); counters.getByteCounter(); // 字节大小 counters.getDirectoryCounter(); // 目录个数 counters.getFileCounter(); // 文件个数 |
三、流相关
org.apache.commons.io.input和org.apache.commons.io.output包下有许多好用的过滤流。
1、自动关闭的输入流 AutoCloseInputStream
AutoCloseInputStream是一个过滤流,用来包装其他流,读取完后流会自动关掉
实现原理很简单,当读取完后将底层的流关闭,然后创建一个ClosedInputStream赋值给它包装的输入流。
注:如果输入流没有全部读取是不会关掉底层流的
01 02 03 04 05 06 07 08 09 10 | /** * AutoCloseInputStream是一个过滤流,用来包装其他流,读取完后流会自动关掉 * 实现原理很简单,当读取完后将底层的流关闭,然后创建一个ClosedInputStream赋值给它包装的输入流。 * 注:如果输入流没有全部读取是不会关掉底层流的 */ public void autoCloseDemo() throws Exception { InputStream is = new FileInputStream( "test.txt" ); AutoCloseInputStream acis = new AutoCloseInputStream(is); IOUtils.toByteArray(acis); // 将流全部读完 // 可以省略关闭流的逻辑了 } |
2、倒序文件读取 ReversedLinesFileReader
1 2 3 4 5 | // 从后向前按行读取 try (ReversedLinesFileReader reader = new ReversedLinesFileReader( new File( "test.txt" ), Charset.forName( "UTF-8" ))) { String lastLine = reader.readLine(); // 读取最后一行 List<String> line5 = reader.readLines( 5 ); // 从后再读5行 } |
3、带计数功能的流 CountingInputStream,CountingOutputStream
只给一个输入流是没办法准确的知道它的大小的,虽说流提供了available()方法。但是这个方法只有在ByteArrayInputStream的情况下拿到的是准确的大小,其他如文件流网络流等都是不准确的(当然用野路子也可以实现,比如写入临时文件通过File.length()方法获取,然后在将文件转换为文件流)
01 02 03 04 05 06 07 08 09 10 11 | /** * 下面这个流可以实现计数功能,当把文件读完大小也就计算出来了 */ public void countingDemo() { InputStream is = new FileInputStream( "test.txt" ); try (CountingInputStream cis = new CountingInputStream(is)) { String txt = IOUtils.toString(cis, "UTF-8" ); // 文件内容 long size = cis.getByteCount(); // 读取的字节数 } catch (IOException e) { // 异常处理 } } |
4、可观察的输入流 ObservableInputStream
可观察的输入流(典型的观察者模式),可实现边读取边处理。比如将某些字节替换为另一个字节,计算md5摘要等。当然也可以完全写到文件后在做处理,这样相当于做了两次遍历,性能较差。
这是一个基类,使用时需要继承它来扩展自己的流,示例如下:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | private class MyObservableInputStream extends ObservableInputStream { class MyObserver extends Observer { @Override public void data( final int input) throws IOException { // 做自定义处理 } @Override public void data( final byte [] input, final int offset, final int length) throws IOException { // 做自定义处理 } } public MyObservableInputStream(InputStream inputStream) { super (inputStream); } } |
5、其他
- BOMInputStream:同时读取文本文件的bom头
- BoundedInputStream:有界的流,控制只允许读取前x个字节
- BrokenInputStream:一个错误流,永远抛出IOException
- CharSequenceInputStream:支持StringBuilder,StringBuffer等读取
- LockableFileWriter:带锁的Writer,同一个文件同时只允许一个流写入,多余的写入操作会跑出IOException
- StringBuilderWriter:StringBuilder的Writer
四、文件比较器
org.apache.commons.io.compare包有很多现成的文件比较器,可以对文件排序的时候直接拿来用。
- DefaultFileComparator:默认文件比较器,直接使用File的compare方法。(文件集合排序( Collections.sort() )时传此比较器和不传效果一样)
- DirectoryFileComparator:目录排在文件之前
- ExtensionFileComparator:扩展名比较器,按照文件的扩展名的ascii顺序排序,无扩展名的始终排在前面
- LastModifiedFileComparator:按照文件的最后修改时间排序
- NameFileComparator:按照文件名称排序
- PathFileComparator:按照路径排序,父目录优先排在前面
- SizeFileComparator:按照文件大小排序,小文件排在前面(目录会计算其总大小)
- CompositeFileComparator:组合排序,将以上排序规则组合在一起
示例如下:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | List<File> files = Arrays.asList(new File[]{ new File("/foo/def"), new File("/foo/test.txt"), new File("/foo/abc"), new File("/foo/hh.txt")}); // 排序目录在前 Collections.sort(files, DirectoryFileComparator.DIRECTORY_COMPARATOR); // ["/foo/def", "/foo/abc", "/foo/test.txt", "/foo/hh.txt"] // 排序目录在后 Collections.sort(files, DirectoryFileComparator.DIRECTORY_REVERSE); // ["/foo/test.txt", "/foo/hh.txt", "/foo/def", "/foo/abc"] // 组合排序,首先按目录在前排序,其次再按照名称排序 Comparator dirAndNameComp = new CompositeFileComparator( DirectoryFileComparator.DIRECTORY_COMPARATOR, NameFileComparator.NAME_COMPARATOR); Collections.sort(files, dirAndNameComp); // ["/foo/abc", "/foo/def", "/foo/hh.txt", "/foo/test.txt"] |
五、文件监视器
org.apache.commons.io.monitor包主要提供对文件的创建、修改、删除的监听操作。
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public static void main(String[] args) throws Exception { // 监听目录下文件变化。可通过参数控制监听某些文件,默认监听目录所有文件 FileAlterationObserver observer = new FileAlterationObserver( "/foo" ); observer.addListener( new myListener()); FileAlterationMonitor monitor = new FileAlterationMonitor(); monitor.addObserver(observer); monitor.start(); // 启动监视器 Thread.currentThread().join(); // 避免主线程退出造成监视器退出 } private class myListener extends FileAlterationListenerAdaptor { @Override public void onFileCreate(File file) { System.out.println( "fileCreated:" + file.getAbsolutePath()); } @Override public void onFileChange(File file) { System.out.println( "fileChanged:" + file.getAbsolutePath()); } @Override public void onFileDelete(File file) { System.out.println( "fileDeleted:" + file.getAbsolutePath()); } } |