【一】Apache commons IO包之IOUtils
前面我们已经学习了FileUtils,知道了Apache commons IO包提供了很多实用的工具来对文件进行操作。但是它们的底层到底是怎么实现的呢?如果现在我们要操作的不是文件,而是网络资源呢?
其实FileUtils的基石就是IOUtils,它内置了大量的简化方法来简化IO读写操作和提供默认的缓冲支持。看看官网的说法:
【二】IOUtils的常用API及解析
①读操作
IOUtils类提供的读操作方法有两大类:第一类是readLines方法。第二类是toXxx方法。
※ readLines方法
List readLines(InputStream input)
List readLines(InputStream input, String encoding)
readLines(Reader input)
我们知道在字节流中是没有“行”的概念的,但是为什么这里的readLines方法可以接收InputStream呢?看看源代码就知道了
public static List readLines(InputStream input, String encoding) throws IOException {
if (encoding == null) {
return readLines(input);
} else {
InputStreamReader reader = new InputStreamReader(input, encoding);
return readLines(reader);
}
}
public static List readLines(Reader input) throws IOException {
BufferedReader reader = new BufferedReader(input);
List list = new ArrayList();
String line = reader.readLine();
while (line != null) {
list.add(line);
line = reader.readLine();
}
return list;
}
原来在底层,IOUtils使用了InputStreamReader对input stream进行了包装,到了readLines(Reader)方法内,又再加了一个缓冲。如果我们是直接调用readLines(Reader)方法,为了确保编码正确,需要手工创建一个InputStreamReader并指明encoding,否则将采用默认的encoding。
※ toXxx方法
IOUtils支持把input stream中的数据转换成byte[],char[],String对象。而且input stream可以是字节流,字符流。同时可以指定encoding。这些方法实质上是“输出”的过程:即从输入流中读入数据,然后转换为byte[],char[],String,输出到内存中。看看下面的一个源代码:
public static char[] toCharArray(InputStream is, String encoding)
throws IOException {
CharArrayWriter output = new CharArrayWriter();
copy(is, output, encoding);
return output.toCharArray();
}
public static void copy(InputStream input, Writer output, String encoding)
throws IOException {
if (encoding == null) {
copy(input, output);
} else {
InputStreamReader in = new InputStreamReader(input, encoding);
copy(in, output);
}
}
public static int copy(Reader input, Writer output) throws IOException {
long count = copyLarge(input, output);
if (count > Integer.MAX_VALUE) {
return -1;
}
return (int) count;
}
public static long copyLarge(Reader input, Writer output) throws IOException {
char[] buffer = new char[DEFAULT_BUFFER_SIZE];
long count = 0;
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
我们可以看到这个过程是没有进行flush的操作的,也就是说使用者必须负责在调用结束后进行缓存清空和输入、输入流关闭。对于input stream是文件的情况,在FileUtils的文件读方法的最后都会调用IOUtils.closeQuietly(in);方法来确保输入流正确关闭。
②写操作
和读操作一样,IOUtils一样提供了大量的写方法,这些方法可以将byte[],char[],StringBuffer,String,Collection中的数据以字节流,字符流的形式写入到目的源。
※ writeLines方法
public static void writeLines(Collection lines, String lineEnding,
OutputStream output, String encoding) throws IOException {
if (encoding == null) {
writeLines(lines, lineEnding, output);
} else {
if (lines == null) {
return;
}
if (lineEnding == null) {
lineEnding = LINE_SEPARATOR;
}
for (Iterator it = lines.iterator(); it.hasNext(); ) {
Object line = it.next();
if (line != null) {
output.write(line.toString().getBytes(encoding));
}
output.write(lineEnding.getBytes(encoding));
}
}
}
public static void writeLines(Collection lines, String lineEnding,
Writer writer) throws IOException {
if (lines == null) {
return;
}
if (lineEnding == null) {
lineEnding = LINE_SEPARATOR;
}
for (Iterator it = lines.iterator(); it.hasNext(); ) {
Object line = it.next();
if (line != null) {
writer.write(line.toString());
}
writer.write(lineEnding);
}
}
如果我们查看FileUtils,会发现它对所有的文件读写(包括writeLines,writeStringToFile),都是调用字节流+encoding的方式来进行的。因为所有基于字符流的方式最终都需要转换为基于字节流的方式。
③流拷贝
我们在从文件等数据源读入数据时,习惯性地以字节读入,到了内存又转换成String对象,最后修改性地以字符写回文件。IOUtils提供了一系列方便的方法来进行这中间的转换。
copy(InputStream input, Writer output, String encoding),这个方法使用指定的encoding,从字节流中读入字节,然后按照encoding解码,通过字符流写回目的源。
copy(Reader input, OutputStream output, String encoding),这个方法从字符流中读取字符,使用指定的encoding编码,通过字节流写回目的源,然后立即清空缓冲。
上面这两个方法底层都调用了一个名为copyLarge的方法,他们分别在通过一个byte[]或者char[]数组对要写回的内容进行缓冲。一次性地从源端读入4K数据然后通过输出流写回。
public static long copyLarge(InputStream input, OutputStream output)
throws IOException {
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
long count = 0;
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
public static long copyLarge(Reader input, Writer output) throws IOException {
char[] buffer = new char[DEFAULT_BUFFER_SIZE];
long count = 0;
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
④内容比较
这一点在前面FileUtils.contentEquals(File, File)方法中已经有提及,请参考上一篇文章
-------------------------------------------------------------
生活就像打牌,不是要抓一手好牌,而是要尽力打好一手烂牌。
posted on 2010-03-08 21:24
Paul Lin 阅读(2381)
评论(0) 编辑 收藏 所属分类:
J2SE