Java IO即Java 輸入輸出系統。無論咱們編寫何種應用,都不免和各類輸入輸出相關的媒介打交道,其實和媒介進行IO的過程是十分複雜的,這要考慮的因素特別多,好比咱們要考慮和哪一種媒介進行IO(文件、控制檯、網絡),咱們還要考慮具體和它們的通訊方式(順序、隨機、二進制、按字符、按字、按行等等)。Java類庫的設計者經過設計大量的類來攻克這些難題,這些類就位於java.io包中。html
在JDK1.4以後,爲了提升Java IO的效率,Java又提供了一套新的IO,Java New IO簡稱Java NIO。它在標準java代碼中提供了高速的面向塊的IO操做。本篇文章重點介紹Java IO,關於Java NIO請參考個人另兩篇文章: java
高級Java工程師必備 ----- 深刻分析 Java IO (一)BIO網絡
高級Java工程師必備 ----- 深刻分析 Java IO (二)NIO框架
首先看個圖:dom
雖然java IO類庫龐大,但整體來講其框架仍是很清楚的。從是讀媒介仍是寫媒介的維度看,Java IO能夠分爲:性能
而從其處理流的類型的維度上看,Java IO又能夠分爲:spa
下面這幅圖就清晰的描述了JavaIO的分類:設計
- | 字節流 | 字符流 |
---|---|---|
輸入流 | InputStream | Reader |
輸出流 | OutputStream | Writer |
咱們的程序須要經過InputStream或Reader從數據源讀取數據,而後用OutputStream或者Writer將數據寫入到目標媒介中。其中,InputStream和Reader與數據源相關聯,OutputStream和writer與目標媒介相關聯。指針
經過上面的介紹咱們已經知道,字節流對應的類應該是InputStream和OutputStream,而在咱們實際開發中,咱們應該根據不一樣的媒介類型選用相應的子類來處理。下面咱們就用字節流來操做文件媒介:code
例1,用字節流寫文件
public static void writeByteToFile() throws IOException{ String hello= new String( "hello word!"); byte[] byteArray= hello.getBytes(); File file= new File( "d:/test.txt"); //由於是用字節流來寫媒介,因此對應的是OutputStream //又由於媒介對象是文件,因此用到子類是FileOutputStream OutputStream os= new FileOutputStream( file); os.write( byteArray); os.close(); }
例2,用字節流讀文件
public static void readByteFromFile() throws IOException{ File file= new File( "d:/test.txt"); byte[] byteArray= new byte[( int) file.length()]; //由於是用字節流來讀媒介,因此對應的是InputStream //又由於媒介對象是文件,因此用到子類是FileInputStream InputStream is= new FileInputStream( file); int size= is.read( byteArray); System. out.println( "大小:"+size +";內容:" +new String(byteArray)); is.close(); }
package com.chenhao.io.byteIO; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * @author ChenHao * */ public class CopyFileDemo { /** * @param args * @throws FileNotFoundException */ public static void main(String[] args) { String src ="E:/xp/test"; String dest="e:/xp/test/4.jpg"; try { copyFile(src,dest); } catch (FileNotFoundException e) { e.printStackTrace(); System.out.println("文件不存在"); } catch (IOException e) { e.printStackTrace(); System.out.println("拷貝文件失敗|關閉流失敗"); } } /** * 文件的拷貝 * @param 源文件路徑 * @param 目錄文件路徑 * @throws FileNotFoundException,IOException * @return */ public static void copyFile(String srcPath,String destPath) throws FileNotFoundException,IOException { //一、創建聯繫 源(存在且爲文件) +目的地(文件能夠不存在) File src =new File(srcPath); File dest =new File(destPath); if(! src.isFile()){ //不是文件或者爲null System.out.println("只能拷貝文件"); throw new IOException("只能拷貝文件"); } //二、選擇流 InputStream is =new FileInputStream(src); OutputStream os =new FileOutputStream(dest); //三、文件拷貝 循環+讀取+寫出 byte[] flush =new byte[1024]; int len =0; //讀取 while(-1!=(len=is.read(flush))){ //寫出 os.write(flush, 0, len); } os.flush(); //強制刷出 //關閉流 os.close(); is.close(); } }
一樣,字符流對應的類應該是Reader和Writer。下面咱們就用字符流來操做文件媒介:
例3,用字符流讀文件
public static void writeCharToFile() throws IOException{ String hello= new String( "hello word!"); File file= new File( "d:/test.txt"); //由於是用字符流來讀媒介,因此對應的是Writer,又由於媒介對象是文件,因此用到子類是FileWriter Writer os= new FileWriter( file); os.write( hello); os.close(); }
例4,用字符流寫文件
public static void readCharFromFile() throws IOException{ File file= new File( "d:/test.txt"); //由於是用字符流來讀媒介,因此對應的是Reader //又由於媒介對象是文件,因此用到子類是FileReader Reader reader= new FileReader( file); char [] byteArray= new char[( int) file.length()]; int size= reader.read( byteArray); System. out.println( "大小:"+size +";內容:" +new String(byteArray)); reader.close(); }
字節流能夠轉換成字符流,java.io包中提供的InputStreamReader類就能夠實現,固然從其命名上就能夠看出它的做用。其實這涉及到另外一個概念,IO流的組合,後面咱們詳細介紹。下面看一個簡單的例子:
例5 ,字節流轉換爲字符流
public static void convertByteToChar() throws IOException{ File file= new File( "d:/test.txt"); //得到一個字節流 InputStream is= new FileInputStream( file); //把字節流轉換爲字符流,其實就是把字符流和字節流組合的結果。 Reader reader= new InputStreamReader( is); char [] byteArray= new char[( int) file.length()]; int size= reader.read( byteArray); System. out.println( "大小:"+size +";內容:" +new String(byteArray)); is.close(); reader.close(); }
例6 ,File操做
public class FileDemo { public static void main(String[] args) { //檢查文件是否存在 File file = new File( "d:/test.txt"); boolean fileExists = file.exists(); System. out.println( fileExists); //建立文件目錄,若父目錄不存在則返回false File file2 = new File( "d:/fatherDir/subDir"); boolean dirCreated = file2.mkdir(); System. out.println( dirCreated); //建立文件目錄,若父目錄不存則連同父目錄一塊兒建立 File file3 = new File( "d:/fatherDir/subDir2"); boolean dirCreated2 = file3.mkdirs(); System. out.println( dirCreated2); File file4= new File( "d:/test.txt"); //判斷長度 long length = file4.length(); //重命名文件 boolean isRenamed = file4.renameTo( new File("d:/test2.txt")); //刪除文件 boolean isDeleted = file4.delete(); File file5= new File( "d:/fatherDir/subDir"); //是不是目錄 boolean isDirectory = file5.isDirectory(); //列出文件名 String[] fileNames = file5.list(); //列出目錄 File[] files = file4.listFiles(); } }
經過上面的例子咱們已經知道,咱們能夠用FileInputStream(文件字符流)或FileReader(文件字節流)來讀文件,這兩個類可讓咱們分別以字符和字節的方式來讀取文件內容,可是它們都有一個不足之處,就是隻能從文件頭開始讀,而後讀到文件結束。
可是有時候咱們只但願讀取文件的一部分,或者是說隨機的讀取文件,那麼咱們就能夠利用RandomAccessFile。RandomAccessFile提供了seek()
方法,用來定位將要讀寫文件的指針位置,咱們也能夠經過調用getFilePointer()
方法來獲取當前指針的位置,具體看下面的例子:
例7,隨機讀取文件
public static void randomAccessFileRead() throws IOException { // 建立一個RandomAccessFile對象 RandomAccessFile file = new RandomAccessFile( "d:/test.txt", "rw"); // 經過seek方法來移動讀寫位置的指針 file.seek(10); // 獲取當前指針 long pointerBegin = file.getFilePointer(); // 從當前指針開始讀 byte[] contents = new byte[1024]; file.read( contents); long pointerEnd = file.getFilePointer(); System. out.println( "pointerBegin:" + pointerBegin + "\n" + "pointerEnd:" + pointerEnd + "\n" + new String(contents)); file.close(); }
例8,隨機寫入文件
public static void randomAccessFileWrite() throws IOException { // 建立一個RandomAccessFile對象 RandomAccessFile file = new RandomAccessFile( "d:/test.txt", "rw"); // 經過seek方法來移動讀寫位置的指針 file.seek(10); // 獲取當前指針 long pointerBegin = file.getFilePointer(); // 從當前指針位置開始寫 file.write( "HELLO WORD".getBytes()); long pointerEnd = file.getFilePointer(); System. out.println( "pointerBegin:" + pointerBegin + "\n" + "pointerEnd:" + pointerEnd + "\n" ); file.close(); }
BufferedInputStream顧名思義,就是在對流進行寫入時提供一個buffer來提升IO效率。在進行磁盤或網絡IO時,原始的InputStream對數據讀取的過程都是一個字節一個字節操做的,而BufferedInputStream在其內部提供了一個buffer,在讀數據時,會一次讀取一大塊數據到buffer中,這樣比單字節的操做效率要高的多,特別是進程磁盤IO和對大量數據進行讀寫的時候,能提高IO性能。
使用BufferedInputStream十分簡單,只要把普通的輸入流和BufferedInputStream組合到一塊兒便可。咱們把上面的例2改形成用BufferedInputStream進行讀文件,請看下面例子:
例10 ,用緩衝流讀文件
public static void readByBufferedInputStream() throws IOException { File file = new File( "d:/test.txt"); byte[] byteArray = new byte[( int) file.length()]; //能夠在構造參數中傳入buffer大小 InputStream is = new BufferedInputStream( new FileInputStream(file),2*1024); int size = is.read( byteArray); System. out.println( "大小:" + size + ";內容:" + new String(byteArray)); is.close(); }
BufferedOutputStream的狀況和BufferedInputStream一致,在這裏就很少作描述了。
package com.chenhao.io.buffered; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * 字節流文件拷貝+緩衝流 ,提升性能 * 緩衝流(節點流) * @author ChenHao * */ public class BufferedByteDemo { public static void main(String[] args) { String src ="E:/xp/test"; String dest="e:/xp/test/4.jpg"; try { copyFile(src,dest); } catch (FileNotFoundException e) { e.printStackTrace(); System.out.println("文件不存在"); } catch (IOException e) { e.printStackTrace(); System.out.println("拷貝文件失敗|關閉流失敗"); } } /** * 文件的拷貝 * @param 源文件路徑 * @param 目錄文件路徑 * @throws FileNotFoundException,IOException * @return */ public static void copyFile(String srcPath,String destPath) throws FileNotFoundException,IOException { //一、創建聯繫 源(存在且爲文件) +目的地(文件能夠不存在) File src =new File(srcPath); File dest =new File(destPath); if(! src.isFile()){ //不是文件或者爲null System.out.println("只能拷貝文件"); throw new IOException("只能拷貝文件"); } //二、選擇流 InputStream is =new BufferedInputStream(new FileInputStream(src)); OutputStream os =new BufferedOutputStream( new FileOutputStream(dest)); //三、文件拷貝 循環+讀取+寫出 byte[] flush =new byte[1024]; int len =0; //讀取 while(-1!=(len=is.read(flush))){ //寫出 os.write(flush, 0, len); } os.flush(); //強制刷出 //關閉流 os.close(); is.close(); } }
BufferedReader、BufferedWriter 的做用基本和BufferedInputStream、BufferedOutputStream一致,具體用法和原理都差很少 ,只不過一個是面向字符流一個是面向字節流。一樣,咱們將改造字符流中的例4,給其加上buffer功能,看例子:
public static void readByBufferedReader() throws IOException { File file = new File( "d:/test.txt"); // 在字符流基礎上用buffer流包裝,也能夠指定buffer的大小 Reader reader = new BufferedReader( new FileReader(file),2*1024); char[] byteArray = new char[( int) file.length()]; int size = reader.read( byteArray); System. out.println( "大小:" + size + ";內容:" + new String(byteArray)); reader.close(); }
另外,BufferedReader提供一個readLine()能夠方便地讀取一行,而FileInputStream和FileReader只能讀取一個字節或者一個字符,所以BufferedReader也被稱爲行讀取器.
public static void keyIn() throws IOException { try (//InputStreamReader是從byte轉成char的橋樑 InputStreamReader reader = new InputStreamReader(System.in); //BufferedReader(Reader in)是char類型輸入的包裝類 BufferedReader br = new BufferedReader(reader);) { String line = null; while ((line = br.readLine()) != null) { if (line.equals("exit")) { //System.exit(1); break; } System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } }
若是你但願類可以序列化和反序列化,必須實現Serializable接口,就像所展現的ObjectInputStream和ObjectOutputStream例子同樣。
ObjectInputStream可以讓你從輸入流中讀取Java對象,而不須要每次讀取一個字節。你能夠把InputStream包裝到ObjectInputStream中,而後就能夠從中讀取對象了。代碼以下:
ObjectInputStream input = new ObjectInputStream(new FileInputStream("object.data")); MyClass object = (MyClass) input.readObject(); //etc. input.close();
在這個例子中,你讀取的對象必須是MyClass的一個實例,而且必須事先經過ObjectOutputStream序列化到「object.data」文件中。
在你序列化和反序列化一個對象以前,該對象的類必須實現了java.io.Serializable接口。
ObjectOutputStream可以讓你把對象寫入到輸出流中,而不須要每次寫入一個字節。你能夠把OutputStream包裝到ObjectOutputStream中,而後就能夠把對象寫入到該輸出流中了。代碼以下:
ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("object.data")); MyClass object = new MyClass(); output.writeObject(object); //etc. output.close();
例子中序列化的對象object如今能夠從ObjectInputStream中讀取了。
一樣,在你序列化和反序列化一個對象以前,該對象的類必須實現了java.io.Serializable接口。
原文出處:https://www.cnblogs.com/java-chen-hao/p/11083740.html