標籤:
一、概述
Java的IO支援通過java.io包下的類和介面來完成,在java.io包下主要有包括輸入、輸出兩種IO流,每種輸入輸出資料流又可分為位元組流和字元流兩大類。從JDK1.4以後,Java在java.nio包下提供了系列的全新API,通過java.nio,程式可以更高效的進行輸入、輸出操作。
二、Java I/O類和介面
- File類
File類直接處理檔案和檔案系統,它沒有指定如何擷取資訊或將資訊儲存到檔案中,只描述了檔案本身的屬性。File對象用於獲得或者操作與磁碟檔案相關聯的資訊,如存取許可權、時間、日期和目錄路徑等,並且還可以瀏覽子目錄的階層。
下面的建構函式可用來建立File對象:
| 構造方法摘要 |
File(File parent, String child) 根據 parent 抽象路徑名和 child 路徑名字串建立一個新 File 執行個體。 |
File(String pathname) 通過將給定路徑名字串轉換為抽象路徑名來建立一個新 File 執行個體。 |
File(String parent, String child) 根據 parent 路徑名字串和 child 路徑名字串建立一個新 File 執行個體。 |
File(URI uri) 通過將給定的 file: URI 轉換為一個抽象路徑名來建立一個新的 File 執行個體。 |
File類定義了許多可以得到File對象標準屬性的方法
public class Demo{ public static void main(String[] args) { File f=new File("D://hello.java"); System.out.println(f.getParent());//返回此抽象路徑名父目錄的路徑名字串;如果此路徑名沒有指定父目錄,則返回 null System.out.println(f.getName());//返回由此抽象路徑名表示的檔案或目錄的名稱 System.out.println(f.exists());//測試此抽象路徑名表示的檔案或目錄是否存在 System.out.println(f.getAbsoluteFile());// 返回此抽象路徑名的絕對路徑名形式 System.out.println(f.getAbsolutePath());//返回此抽象路徑名的規範路徑名字串 System.out.println(f.getPath());//將此抽象路徑名轉換為一個路徑名字串 System.out.println(f.hashCode());//計算此抽象路徑名的雜湊碼 System.out.println(f.length());//返回由此抽象路徑名表示的檔案的長度 System.out.println(f.list());// 返回一個字串數組,這些字串指定此抽象路徑名表示的目錄中的檔案和目錄 System.out.println(f.mkdir());//建立此抽象路徑名指定的目錄 }} 2. 流類
Java中把不同的輸入輸出源抽象畫為“流”,通過流的方式允許?Java程式使用相同的方式來訪問不同的輸入輸出源。
位元組流類:提供了處理針對位元組的IO的豐富環境,頂部類是InputStream和OutputStream,它們均是抽象類別。
字元流類:位元組流類不能處理Unicode字元,字元流類操作的資料單元為字元,,頂部類是Reader和Writer。
位元組流類和字元流類的功能基本一樣,只是操作的資料單元不同,其中InputStream和Reader都是將資料抽象為一根水管,程式可以通過read()方法每次抽取一個“水滴”,也可以通過read(char[] cbuf)方法來讀取多個“水滴”,程式通過read()方法返回-1來判斷是否到了輸入資料流的結束點。
eg.讀取檔案,統計檔案字元數:
public class FileDemo{ public static void main(String[] args) { int b=0; try { FileInputStream in=null; in =new FileInputStream("D:\\a.txt"); long num=0; while((b=in.read())!=-1) { System.out.print((char)b); num++; } in.close(); System.out.println(num); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }}
FileInputStream類建立一個InputStream,可以用來從檔案中讀取檔案。
eg.將一個檔案內容拷貝至另一個檔案:
public class FileOutStream{ public static void main(String[] args) { int b=0; try { FileInputStream in =new FileInputStream("D:\\Eclipse\\workSpace\\day_041602\\src\\day_041602\\TestMain.java"); FileOutputStream out=new FileOutputStream("D:\\hello.java"); while((b=in.read())!=-1) { out.write(b); } in.close(); out.close(); System.out.println("執行完成"); } catch (FileNotFoundException e) { // TODO 自動產生的 catch 塊 e.printStackTrace(); } catch (IOException e) { // TODO 自動產生的 catch 塊 e.printStackTrace(); } }}
BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter稱為緩衝流,它們通過緩衝輸入輸出來提高效能。
eg.在hello.java文本中輸入100個隨機數,並在螢幕上顯示:
public class BufferWriterDemo{ public static void main(String[] args) { try { String s; BufferedWriter bw=new BufferedWriter(new FileWriter("D:\\hello.java")); BufferedReader br=new BufferedReader(new FileReader("D:\\hello.java")); for(int i=0;i<100;i++) { s=String.valueOf(Math.random()); //產生隨機數 bw.write(s);//寫入hello.java檔案中 bw.newLine();//寫入一個分行符號 } bw.flush();//重新整理緩衝 while((s=br.readLine()) != null)//讀取一個文本行 { System.out.println(s); } bw.close(); br.close(); } catch (IOException e) { // TODO 自動產生的 catch 塊 e.printStackTrace(); } }} 三、NIO 1.概述
NIO使用記憶體映射的方式處理輸入輸出,將檔案或檔案的一段區域對應到記憶體中,這樣就可以像訪問記憶體一樣來訪問檔案了。
相關的包有:java.nio.channels包:主要包含Channel和Selector相關的類,java.nio.charset包:主要包含和字元集相關的類
NIO系基於兩個基本的元素:緩衝和通道。緩衝區容納資料,通道代表隊I/O裝置的開放式串連。一般而言使用NIO系統,需要獲得到I?O裝置的一個通道和容納資料的一個緩衝區,然後可以對緩衝區進行操作,隨意輸入和輸出資料。除此之外,NIO還提供了用於將Unicode字串映射成位元組序列以及逆映射操作的Charset類,還有支援非阻塞式輸入輸出的Selector類。
2.緩衝區
緩衝(buffer)可以理解成一個容器,它的本質是一個數組,發送到Channel中的所有對象都必須首先放到buffer中,從channel中讀取的資料也必須先讀到buffer中。
Buffer中有三個重要的參數:
-
- capacity:表示該Buffer的最大儲存容量
- limit:第一個不應該被讀出或寫入的緩衝區位置索引
- position:用於指明下一個可以被讀出或寫入的緩衝區位置索引
除此之外還有一個可選的mark標記,該mark允許程式直接將position定位到mark處。位置如下所示:
每放入一個資料,position向後移動一位,當Buffer裝入資料結束後,調用flip方法,將limit設定為position所在的位置,將position設定為0,這樣使得從Buffer中讀資料總是從0開始。當Buffer輸出資料結束後,Buffer調用 clear方法,它將position置為0,,置limit為capacity,這樣為再次向Buffer中裝入資料做好準備。Buffer還提供了put和get方法,用於向Buffer中放入資料和讀取資料,既支援對單個資料的訪問也支援對批量資料的訪問。
eg.
public class Test{ public static void main(String[] args) { CharBuffer m=CharBuffer.allocate(8); m.put(‘a‘); m.put(‘b‘); m.put(‘c‘); System.out.println("position:"+m.position()); System.out.println("limit:"+m.limit()); m.flip(); System.out.println("第一個元素"+m.get()); System.out.println("第二個元素"+m.get()); System.out.println("position:"+m.position()); }}
執行結果:
3.通道
Channel與傳統的InputStream、OutputStream最大的區別在於它提供了一個map方法,通過該map方法可以直接將一塊資料對應到記憶體中。
Channel是一個介面,系統為該介面提供了FileChannel等實作類別,所有的Channel都是通過傳統節點InputStream、OutputSteam的getChannel方法來返回對應的Channel。
Channel中最常見的三個方法是:map、read和write。其中map將Channel對應的部分或全部資料對應的ByteBuffer,read或write方法有一系列重載的形式用於讀取資料。
eg.將WelcomeServlet.java的內容複寫到a.txt中去,並在控制台列印處內容。
public class FileChannelTest{ public static void main(String[] args) { FileChannel inChannel=null; FileChannel outChannel=null; FileChannel randomChannel=null; File f=new File("D://WelcomeServlet.java"); try { FileInputStream fs=new FileInputStream(f); inChannel=fs.getChannel(); MappedByteBuffer buffer=inChannel.map(FileChannel.MapMode.READ_ONLY,0, f.length());//將inChannel裡的全部資料對應成ByteBuffer Charset charset=Charset.forName("GBK"); outChannel=new FileOutputStream("D://a.txt").getChannel(); outChannel.write(buffer); buffer.clear(); CharsetDecoder decoder=charset.newDecoder();//建立解碼器對象 CharBuffer charBuffer=decoder.decode(buffer);//使用解碼器將ByteBuffer轉換為charBuffer System.out.println(charBuffer); //擷取對應字串 } catch (FileNotFoundException e) { // TODO 自動產生的 catch 塊 e.printStackTrace(); } catch (IOException e) { // TODO 自動產生的 catch 塊 e.printStackTrace(); } }}
Java的I/O操作