【一】Apache commons IO包之IOUtils
前面我們已經(jīng)學(xué)習(xí)了FileUtils,知道了Apache commons IO包提供了很多實(shí)用的工具來對文件進(jìn)行操作。但是它們的底層到底是怎么實(shí)現(xiàn)的呢?如果現(xiàn)在我們要操作的不是文件,而是網(wǎng)絡(luò)資源呢?
其實(shí)FileUtils的基石就是IOUtils,它內(nèi)置了大量的簡化方法來簡化IO讀寫操作和提供默認(rèn)的緩沖支持。看看官網(wǎng)的說法:

【二】IOUtils的常用API及解析
①讀操作
IOUtils類提供的讀操作方法有兩大類:第一類是readLines方法。第二類是toXxx方法。
※ readLines方法
List readLines(InputStream input)
List readLines(InputStream input, String encoding)
readLines(Reader input)
我們知道在字節(jié)流中是沒有“行”的概念的,但是為什么這里的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進(jìn)行了包裝,到了readLines(Reader)方法內(nèi),又再加了一個緩沖。如果我們是直接調(diào)用readLines(Reader)方法,為了確保編碼正確,需要手工創(chuàng)建一個InputStreamReader并指明encoding,否則將采用默認(rèn)的encoding。
※ toXxx方法
IOUtils支持把input stream中的數(shù)據(jù)轉(zhuǎn)換成byte[],char[],String對象。而且input stream可以是字節(jié)流,字符流。同時可以指定encoding。這些方法實(shí)質(zhì)上是“輸出”的過程:即從輸入流中讀入數(shù)據(jù),然后轉(zhuǎn)換為byte[],char[],String,輸出到內(nèi)存中。看看下面的一個源代碼:
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;
}


我們可以看到這個過程是沒有進(jìn)行flush的操作的,也就是說使用者必須負(fù)責(zé)在調(diào)用結(jié)束后進(jìn)行緩存清空和輸入、輸入流關(guān)閉。對于input stream是文件的情況,在FileUtils的文件讀方法的最后都會調(diào)用IOUtils.closeQuietly(in);方法來確保輸入流正確關(guān)閉。
②寫操作
和讀操作一樣,IOUtils一樣提供了大量的寫方法,這些方法可以將byte[],char[],StringBuffer,String,Collection中的數(shù)據(jù)以字節(jié)流,字符流的形式寫入到目的源。
※ 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,會發(fā)現(xiàn)它對所有的文件讀寫(包括writeLines,writeStringToFile),都是調(diào)用字節(jié)流+encoding的方式來進(jìn)行的。因?yàn)樗谢谧址鞯姆绞阶罱K都需要轉(zhuǎn)換為基于字節(jié)流的方式。
③流拷貝
我們在從文件等數(shù)據(jù)源讀入數(shù)據(jù)時,習(xí)慣性地以字節(jié)讀入,到了內(nèi)存又轉(zhuǎn)換成String對象,最后修改性地以字符寫回文件。IOUtils提供了一系列方便的方法來進(jìn)行這中間的轉(zhuǎn)換。
copy(InputStream input, Writer output, String encoding),這個方法使用指定的encoding,從字節(jié)流中讀入字節(jié),然后按照encoding解碼,通過字符流寫回目的源。
copy(Reader input, OutputStream output, String encoding),這個方法從字符流中讀取字符,使用指定的encoding編碼,通過字節(jié)流寫回目的源,然后立即清空緩沖。
上面這兩個方法底層都調(diào)用了一個名為copyLarge的方法,他們分別在通過一個byte[]或者char[]數(shù)組對要寫回的內(nèi)容進(jìn)行緩沖。一次性地從源端讀入4K數(shù)據(jù)然后通過輸出流寫回。
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;
}
④內(nèi)容比較
這一點(diǎn)在前面FileUtils.contentEquals(File, File)方法中已經(jīng)有提及,請參考上一篇文章
-------------------------------------------------------------
生活就像打牌,不是要抓一手好牌,而是要盡力打好一手爛牌。
posted on 2010-03-08 21:24
Paul Lin 閱讀(2396)
評論(0) 編輯 收藏 所屬分類:
J2SE