1 概述
Commons IO是针对开发IO流功能的工具类库。
主要包括六个区域:
- 工具类——使用静态方法执行共同任务
- 输入——用于InputStream和Reader实现
- 输出——用于OutputStream和Writer实现
- 过滤器——各种文件过滤器实现
- 比较器——各种文件的java.util.Comparator实现
- 文件监听器——监听文件系统事件的组件
2 用户指南
Commons IO包含工具类、endian classes, line iterator, file filters, file comparators and stream implementations.
更多详细描述见javadocs。
2.1 工具类
2.1.1 IOUtils
IOUtils包含处理读、写和复制的工具方法。方法对InputStream、OutputStream、Reader和Writer起作用。
例如,从一个URL读取字节的任务,并且打印它们:
InputStream in = new URL( "http://commons.apache.org" ).openStream(); try { InputStreamReader inR = new InputStreamReader( in ); BufferedReader buf = new BufferedReader( inR ); String line; while ( ( line = buf.readLine() ) != null ) { System.out.println( line ); } } finally { in.close(); } |
使用IOUtils:
InputStream in = new URL( "http://commons.apache.org" ).openStream(); try { System.out.println(IOUtils.toString(in)); } finally { IOUtils.closeQuietly(in); } |
在某些应用领域,这些IO操作是常见的,而这个类可以节省大量的时间。你可以依靠经过良好测试的代码。
这样的实用程序代码,灵活性和速度是最重要的。但是你也应该理解这种方法的局限性。使用上述技术读取一个1 gb文件将导致试图创建一个1 gb的字符串对象!
2.1.2 FileUtils
FileUtils类包含使用File对象的工具方法。包括读写、复制和比较稳健。
读取整个文件行:
File file = new File("/commons/io/project.properties"); List lines = FileUtils.readLines(file, "UTF-8"); |
2.1.3 FilenameUtils
FilenameUtils类包含工具方法不需要使用File对象就可以操作文件名。该类致力于屏蔽Unix和Windows之间的不同,避免这些环境之间的转换(例如,从开发到生产)。
例如,规范文件删除双点片段:
String filename = "C:/commons/io/../lang/project.xml"; 返回 |
2.1.4 FileSystemUtils
FileSystemUtils类包含使用JDK不支持的文件系统访问功能的工具方法。当前,只有获取驱动的空间大小的方法。注意,这是使用的命令行,而不是本地代码。
long freeSpace = FileSystemUtils.freeSpace("C:/"); |
2.2 Endian类
不同的计算机体系采用不同的字节排序约定。在所谓的“Little Endian”的体系结构中(例如Intel),低位字节存储在内存中较低地址,后续字节在较高地址。对于“Big EndIan”体系结构,(例如Motorola),情况恰好相反。
在关联包中有两个类:
- EndianUtils类包含交换Java原始和流的Endian-ness的静态方法。
- SwappedDataInputStream类是DataInput接口的实现。使用它,我们能从非本地EndIan-ness的文件读取数据。
更多细节见http://www.cs.umass.edu/~verts/cs32/endian.html。
2.3 行迭代器
org.apache.commons.io.LineIterator类提供灵活的方式使用一个基于行的文件。可以直接,或通过FileUtils或IOUtils的工厂方法创建实例。推荐使用模式:
处理行 } finally { LineIterator.closeQuietly(iterator); } |
2.4 文件过滤器
org.apache.commons.io.filefilter包定义一个接口(IOFileFilter)包含java.io.FileFilter和java.io.FilenameFilter。此外,包提供一系列随时可用的IOFileFilter接口实现,包括允许你组合其它过滤器的实现。这些过滤器能用于列出文件。
2.5 文件比较器
org.apache.commons.io.comparator包提供一系列java.io.File的java.util.Comparator实现。这些比较器能用于排序文件列表和数组。
2.6 流
org.apache.commons.io.input和org.apache.commons.io.output包含各种有用的流实现。
- 空输出流——默默的吸收发给它的所有数据。
- Tee输出流——发送输出数据到两个流。
- 字节输出输出流——更便捷的JDK类版本。
- 计算流——统计传递的字节数。
- 代理流——委托恰当的方法代理。
- 可锁定的Writer——使用文件锁提供同步的Writer。
3 最佳实践
该文档在IO领域出现一系列“最佳实践”。
3.1 java.io.File
通常,你必须使用文件和文件名。有很多事情可能出错:
- 一个类可以在Unix上工作但不能在Windows上工作(反之亦然)
- 由于双重或丢失路径分隔符的无效路径
- UNC文件名(在Windows上)不使用我的本地文件名功能函数
- 等等
这些都是很好的理由不使用文件名作为字符串。使用java.io.File而不是处理上面的很多中情况。因此,我们最好的实践推荐使用java.io.File而不是文件名字符串避免平台依赖。
Commons-io 1.1包括一个专注于文件名处理的类——FilenameUtils。这处理许多这些文件名问题,然而,任然推荐,尽可能,使用java.io.File对象。
public static String getExtension(String filename) { int index = filename.lastIndexOf(‘.‘); if (index == -1) { return ""; } else { return filename.substring(index + 1); } } |
足够简单?对的,但如果传入一个完整路径而不是一个文件名会发生什么?请看下面,完全合法的路径:“C:\Temp\documentation.new\README”。定义在上面的方法返回“new\README”,肯定不是你想要的。
请使用java.io.File而不是字符串。在FileUtils你将看到围绕java.io.File的功能函数。
不推荐:
String tmpdir = "/var/tmp"; String tmpfile = tmpdir + System.getProperty("file.separator") + "test.tmp"; InputStream in = new java.io.FileInputStream(tmpfile); |
推荐:
File tmpdir = new File("/var/tmp"); File tmpfile = new File(tmpdir, "test.tmp"); InputStream in = new java.io.FileInputStream(tmpfile); |
3.2 缓冲流
IO性能依赖于缓冲策略。通常,读取大小为512或1024字节的数据包速度很快,因为这些大小匹配使用在硬盘上的文件系统或文件系统缓冲中的数据包大小。但只要你多次只读取几个字节,性能肯定下降。
当你读取或输出流尤其是处理文件时确保你正确的缓冲流。只是使用BufferedInputStream装饰你的FileInputStream。
InputStream in = new java.io.FileInputStream(myfile); try { in = new java.io.BufferedInputStream(in); in.read(..... } finally { IOUtils.closeQuietly(in); } |
注意,不要缓冲已经缓冲的流。一些组件像XML解析器可以做自己的缓冲,因此不需要装饰InputStream传入XML解析器,但减慢你的代码。如果你使用CopyUtils或IOUtils不需要使用额外的缓冲流