《Thinking in Java》第18章的內容是相當豐富精彩的,也在網絡學習參考了很多前輩們的筆記,個人由于能力有限(畢竟和大神Bruce Eckel的能力相差甚遠),將這一章的內容分三個部分來寫,希望能夠慢慢品味和領悟Java IO的精粹:
1. 起步:File類
令我很吊胃口的一件事情是,當我翻開圣經,想拜讀Java IO的精髓時,Eckel告訴我,在學習真正用于流讀寫數據的類之前,讓我們先學習如何處理文件目錄問題(潛臺詞仿佛在說,對不起,菜鳥,你得從基礎班開始?。?
File類:Java中File既能代表一個特定文件的名稱,又能代表一個目錄下的一組文件(相當于Files)
我們要學會的是,如何從一個目錄下篩選出我們想要的文件?可以通過目錄過濾器FilenameFilter+正則表達式實現對文件的篩選:
這個用匿名內部類的方式來實現是更合適的,DirFilter在內部實現,使程序變的更小巧靈活:
針對一些文件集上的常用操作我們可以封裝成一個工具類,比如:
Java IO中處理字節流和字符流輸入輸出的基類和派生類繁多,本節主要做兩件事情:(1)給出類的關系圖;(2)回答一個問題,為什么字節流和字符流要分開處理,為什么既要有Reader/Writer,又保留InputStream/OutputStream?
Java IO中分別用到了裝飾者模式和適配者模式。
裝飾模式(Decorator)又稱為包裝模式(Wrapper),通過創建一個裝飾(包裝)對象,來裝飾真實的對象。
Java I/O類庫需要多種不同功能的組合,這正是使用裝飾器模式的理由所在。為什么不使用繼承而采用裝飾器模式呢?如果說Java IO的各種組合是通過繼承方式來實現的話,那么每一種組合都需要一個類,這樣就會出現大量重復性的問題。而通過裝飾器來實現組合,恰恰避免了這個問題。
對于字節流而言,FilterInputStream和FilterOutputStream是用來提供裝飾器接口以控制特定輸入\輸出的兩個類。需要注意的是,對于字符流而言,同樣用到的是裝飾者模式,但是有一點不同,Reader體系中的FilterRead類和InputStream體系中的FilterInputStream的功能不同,它不再是裝飾者。class BufferedReader extends Reader BufferedInputStream:public class BufferedInputStream extends FilterInputStream
舉一個例子如下所示,其中BufferedReader是裝飾對象,FileReader是被裝飾對象。
適配者模式又可以分為類適配方式(類似多繼承)和對象適配方式。而Java IO中使用的是對象適配方式。我們以FileOutputStream為例,可以看到源碼中,FileOutputStream繼承了OutputStream類型,同時持有一個對FileDiscriptor對象的引用。這是一個將FileDiscriptor接口適配成OutputStream接口形式的對象形適配器模式。
本節主要介紹基于字節流的輸入InputStream和輸出OutputStream,以及用于實現裝飾模式的FilterInputStream和FilterOutputStream。
InputStream的作用是表示從不同數據源產生輸入的類:
下面列表展現了InputStream的派生類,所有的派生類都要聯合裝飾類FilterInputStream
ByteArrayInputStream
舉個例子:
需要注意的是StringBufferInputStream已經過時了,JDK給出的過時原因如下:
This class does not properly convert characters into bytes. As of JDK 1.1, the preferred way to create a stream from a string is via the
FileInputStream
管道流可以實現兩個線程之間,二進制數據的傳輸。管道流就像一條管道,一端輸入數據,別一端則輸出數據。通常要分別用兩個不同的線程來控制它們。(這里埋個伏筆,目前筆者對多線程掌握還不夠成熟,等到后面學習Java并發中會繼續提到PipedIntputStream/PipedOutputStream)
舉兩個例子(源于網絡):
另外,還有FilterInputStream,它是抽象類,作為“裝飾器”的接口,筆者將單獨用一節來詳述。
OutputStream的作用是表示從不同數據源產生輸入的類:
下面是OutputStream的派生類。同樣,所有的派生類都要聯合裝飾類FilterOutputStream
ByteArrayOutputStream
與ByteArrayInputStream相對應,public ByteArrayOutputStream() { this(32);
} public ByteArrayOutputStream(int size) { if (size < 0) { throw new IllegalArgumentException("Negative initial size: " + size);
}
buf = new byte[size];
}
與FileInputStream相對應,
PipedOutputStream
FilterInputStream/FilterOutputStream同樣也是InputStream/OutputStream
DataInputStream/DataOutputStream
舉個例子:
該類已經被廢棄了,推薦使用字符流的類來操作。
PushbackInputStream類實現了這一思想,提供了一種機制,可以“偷窺”來自輸入流的內容而不對它們進行破壞。
需要注意的是,與其他輸出流不同, PrintStream 永遠不會拋出 IOException ;它產生的IOException會被自身的函數所捕獲并設置錯誤標記, 用戶可以通過 checkError() 返回錯誤標記,從而查看PrintStream內部是否產生了IOException。
5. 基于字符流的IO操作
設計Reader和Writer繼承層次結構主要是為了國際化的16位Unicode字符編碼。下表展示了Reader/Writer/**
* 文件讀寫工具
*/ package c18; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; public class TextFile { public static String read(String filename) {
StringBuilder sb = new StringBuilder(); try {
BufferedReader in = new BufferedReader(new FileReader( new File(filename).getAbsoluteFile())); try {
String s; while ((s = in.readLine())!= null) {
sb.append(s);
sb.append("\n");
}
} finally {
in.close();
}
} catch (IOException e) { throw new RuntimeException(e);
} return sb.toString();
} public static void write(String filename, String text) { try {
PrintWriter out = new PrintWriter( new File(filename).getAbsoluteFile()); try {
out.print(text);
} finally {
out.close();
}
} catch (IOException e) { throw new RuntimeException(e);
}
}
}
需要注意以下幾點:
1.
參考文獻
感謝并致敬以下前輩的文章:
import java.io.File; import java.io.FilenameFilter; import java.util.Arrays; import java.util.regex.Pattern; /**
* 目錄過濾器
* 顯示符合條件的File對象
* @author 15070229
*
*/ class DirFilter implements FilenameFilter { private Pattern pattern; public DirFilter (String regex) {
pattern = pattern.compile(regex);
} public boolean accept(File dir, String name) { return pattern.matcher(name).matches();
}
} public class DirList { public static void main(String[] args) {
File path = new File(".");
String[] list; if(args.length == 0)
list = path.list(); else list = path.list(new DirFilter(args[0]));
Arrays.sort(list, String.CASE_INSENSITIVE_ORDER); for(String dirItem: list)
System.out.println(dirItem);
}
}
* 通過內部類方式實現的目錄列表器
*/ package c18; import java.io.File; import java.io.FilenameFilter; import java.util.Arrays; import java.util.regex.Pattern; public class DirList2 { public static FilenameFilter filter(final String regex) { //內部類 return new FilenameFilter() { private Pattern pattern = Pattern.compile(regex); @Override public boolean accept(File dir, String name) { return pattern.matcher(name).matches();
}
};
} public static void main(String[] args) {
File path = new File(".");
String[] list; if(args.length == 0)
list = path.list(); else list = path.list(new DirFilter(args[0]));
Arrays.sort(list, String.CASE_INSENSITIVE_ORDER); for(String dirItem: list)
System.out.println(dirItem);
}
}
/**
* 目錄實用工具類
* 本地目錄操作:local方法產生經過正則表達式篩選的本地目錄的文件數組
* 目錄樹操作:walk方法產生給定目錄下的由整個目錄樹中經過正則表達式篩選的文件構成的列表
*/ package c18; import java.io.File; import java.io.FilenameFilter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.regex.Pattern; public final class Directory { /**
* 根據正則表達式,篩選產生File數組
* @param dir
* @param regex
* @return */ public static File[] local(File dir, final String regex) { return dir.listFiles(new FilenameFilter() { private Pattern pattern = Pattern.compile(regex); @Override public boolean accept(File dir, String name) { return pattern.matcher(name).matches();
}
});
} // 方法重載 public static File[] local(String path, final String regex) { return local(new File(path), regex);
} /*
* TreeInfo的使命是收集返回的目錄和文件信息
*/ public static class TreeInfo implements Iterable<File> { public List<File> files = new ArrayList<File>(); public List<File> dirs = new ArrayList<File>(); // public Iterator<File> iterator() { return files.iterator();
} void addAll(TreeInfo other) {
files.addAll(other.files);
dirs.addAll(other.dirs);
} public String toString() { return "dirs:" + PPrint.pformat(dirs) + "\n\nfiles: " + PPrint.pformat(files);
}
} /**
* 遍歷目錄
* @param start
* @param regex
* @return */ public static TreeInfo walk(String start, String regex) { return recurseDirs(new File(start), regex);
} public static TreeInfo walk(File start, String regex) { return recurseDirs(start, regex);
} public static TreeInfo walk(File start) { return recurseDirs(start, ".*");
} public static TreeInfo walk(String start) { return recurseDirs(new File(start), ".*");
} /**
* 遞歸遍歷文件目錄,收集更多的信息(區分普通文件和目錄)
* @param startDir
* @param regex
* @return */ static TreeInfo recurseDirs(File startDir, String regex) {
TreeInfo result = new TreeInfo(); for(File item : startDir.listFiles()) { if (item.isDirectory()) { //持有目錄 result.dirs.add(item);
} else if(item.getName().matches(regex)) //持有普通文件 result.files.add(item);
} return result;
} public static void main(String[] args) { // PPrint.pprint(Directory.walk(".").dirs); // for(File file : Directory.local(".", "T.*"))
System.out.println(file);
}
} /**
- 格式化打印機,打印格式如下:
- [
- .\.settings
- .\bin
- .\src
- ]
*/ class PPrint { public static String pformat(Collection<?> c) { if(c.size() == 0) return "[]";
StringBuilder result = new StringBuilder("["); for(Object elem : c) { if(c.size()!=1)
result.append("\n ");
result.append(elem);
} if(c.size()!=1)
result.append("\n ");
result.append("]"); return result.toString();
} public static void pprint(Collection<?> c) {
System.out.println(pformat(c));
} public static void pprint(Object c) {
System.out.println(Arrays.asList(c));
}
}
2. 字節流和字符流概述
Java 1.0中是只存在InputStream/OutputStream的,設計Reader/Writer
3. 裝飾者模式和適配器模式
裝飾者模式(Decorator)
package c18; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class BufferedInputFile { public static String read(String filename) throws IOException{ //BufferedReader是裝飾對象,FileReader是被裝飾對象 BufferedReader in = new BufferedReader(new FileReader(filename));
String s;
StringBuilder sb = new StringBuilder(); while ((s = in.readLine())!=null) {
sb.append(s + "\n");
}
in.close(); return sb.toString();
}
}
適配者模式(Adapter)
public class FileOutputStream extends OutputStream { private FileDescriptor fd; public FileOutputStream(FileDescriptor fdObj) {
SecurityManager security = System.getSecurityManager(); if (fdObj == null) { throw new NullPointerException();
} if (security != null) {
security.checkWrite(fdObj);
}
fd = fdObj;
fd.incrementAndGetUseCount();
}
}
4. 基于字節流的IO操作
字節流輸入InputStream
/**
* Creates a <code>ByteArrayInputStream
* so that it uses <code>buf as its
* buffer array.
* The buffer array is not copied.
* The initial value of <code>pos
* is <code>0 and the initial value
* of <code>count is the length of
* <code>buf.
*
* @param buf the input buffer.
*/ public ByteArrayInputStream(byte buf[]) { this.buf = buf; this.pos = 0; this.count = buf.length;
}
/**
* 格式化內存輸出
*/ package c18; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.EOFException; import java.io.IOException; public class FormattedMemoryInput { public static void main(String[] args) throws IOException{ try { //DataInputStream面向字節的裝飾類 DataInputStream in = new DataInputStream( new ByteArrayInputStream( //BufferedInputFile.read上例中已經實現了 BufferedInputFile.read("D:/workspace/java_learning/" + "Java_Learning/src/c18/DirList2.java").getBytes())); while (true) { //readByte按字節輸出 System.out.println((char)in.readByte());
}
} catch (EOFException e) {
System.err.println("End of stream");
}
}
}
StringBufferInputStream
//String public FileInputStream(String name) throws FileNotFoundException { this(name != null ? new File(name) : null);
} //File public FileInputStream(File file) throws FileNotFoundException {
String name = (file != null ? file.getPath() : null);
SecurityManager security = System.getSecurityManager(); if (security != null) {
security.checkRead(name);
} if (name == null) { throw new NullPointerException();
}
fd = new FileDescriptor();
fd.incrementAndGetUseCount();
open(name);
} //FileDescriptor public FileInputStream(FileDescriptor fdObj) {
SecurityManager security = System.getSecurityManager(); if (fdObj == null) { throw new NullPointerException();
} if (security != null) {
security.checkRead(fdObj);
}
fd = fdObj;
fd.incrementAndGetUseCount();
}
PipedInputStream
public PipedInputStream(PipedOutputStream src, int pipeSize) throws IOException {
initPipe(pipeSize);
connect(src);
}
SequenceInputStream
public SequenceInputStream(Enumeration<? extends InputStream> e) { this.e = e; try {
nextStream();
} catch (IOException ex) { // This should never happen throw new Error("panic");
}
} public SequenceInputStream(InputStream s1, InputStream s2) {
Vector v = new Vector(2);
v.addElement(s1);
v.addElement(s2);
e = v.elements(); try {
nextStream();
} catch (IOException ex) { // This should never happen throw new Error("panic");
}
}
import java.io.*; import java.util.*;
class SequenceDemo1
{ public static void main(String[] args)throws IOException
{
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("c:\\1.txt"));
v.add(new FileInputStream("c:\\2.txt"));
v.add(new FileInputStream("c:\\3.txt"));
Enumeration<FileInputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("c:\\4.txt"); byte[] buf = new byte[1024]; int len = 0; while((len=sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
}
import java.io.*; import java.util.*;
class SequenceDemo2
{ public static void main(String[] args)throws IOException
{
InputStream is1 = null;
InputStream is2 = null;
OutputStream os = null;
SequenceInputStream sis = new null;
is1 = new FileInputStream("d:"+File.separator+"a.txt");
is2 = new FileInputStream("d:"+File.separator+"b.txt");
os = new FileOutputStream("d:"+File.separator+"ab.txt");
sis = new SequenceInputStream(is1,is2); int temp = 0; while((temp)=sis.read()!=-1)
{
os.write(temp);
}
sis.close();
is1.close();
is2.close();
os.close();
}
}
字節流輸出OutputStream
FileOutputStream
裝飾器FilterInputStream/FilterOutputStream
public DataInputStream(InputStream in) { super(in);
}
public DataOutputStream(OutputStream out) { super(out);
}
BufferedInputStream/BufferedOutputStream
/**
* 使用緩沖區,讀取二級制文件
*/ package c18; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class BinaryFile { public static byte[] read(File bFile) throws IOException {
BufferedInputStream bf = new BufferedInputStream( new FileInputStream(bFile)); try { byte [] data = new byte[bf.available()];
bf.read(data); return data;
} finally {
bf.close();
}
} public static byte[] read(String bFile) throws IOException { return read(new File(bFile).getAbsoluteFile());
}
}
LineNumberInputStream
PushbackInputStream
//允許將size大小的字節回推回流 public PushbackInputStream(InputStream in, int size) { super(in); if (size <= 0) { throw new IllegalArgumentException("size <= 0");
} this.buf = new byte[size]; this.pos = size;
} //每次允許回推一個字節 public PushbackInputStream(InputStream in) { this(in, 1);
}
package c18; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.PushbackInputStream; public class PushbackInputStreamDemo { public static void main(String[] args) { byte[] arrByte = new byte[1024]; byte[] byteArray = new byte[]{'H', 'e', 'l', 'l', 'o',}; /*
* new PushbackInputStream(is, 10)一次能回推10個字節的緩存
*/ InputStream is = new ByteArrayInputStream(byteArray);
PushbackInputStream pis = new PushbackInputStream(is, 10); try { for (int i = 0; i < byteArray.length; i++) {
arrByte[i] = (byte) pis.read();
System.out.print((char) arrByte[i]);
} //換行 System.out.println(); byte[] b = {'W', 'o', 'r', 'l', 'd'}; /*
* unread()回推操作
* 將World回推到PushbackInputStream流中
* 下次read()會將這個字節再次讀取出來
*/ pis.unread(b); for (int i = 0; i < byteArray.length; i++) {
arrByte[i] = (byte) pis.read();
System.out.print((char) arrByte[i]);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
輸出結果:
Hello
World
PrintStream
http://blog.csdn.net/zhangerqing/article/details/8466532
作者:終點
http://blog.csdn.net/yczz/article/details/38761237
作者:yczz
http://www.cnblogs.com/nerxious/archive/2012/12/15/2818848.html
作者:Nerxious
http://www.molotang.com/articles/782.html
作者: 三石·道
http://blog.csdn.net/xuefeng1009/article/details/6955707
作者:xuefeng1009
http://my.oschina.net/fhd/blog/345011
作者:柳哥
http://blog.csdn.net/caixiexin/article/details/6719627
作者:caixiexin
http://www.cnblogs.com/skywang12345/p/io_16.html
作者:skywang12345
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。