Java IO:即Java輸入/輸出系統,區分Java的輸入和輸出:把本身當成程序, 當你從外邊讀數據到本身這裏就用輸入(InputStream/Reader), 向外邊寫數據就用輸出(OutputStream/Writer)。html
Stream:Java中將數據的輸入輸出抽象爲流,流是一組有順序的,單向的,有起點和終點的數據集合,就像水流。按照流中的最小數據單元又分爲字節流和字符流。
1) 字節流:以8位(即1byte, 8bit)做爲一個數據單元,數據流中最小的數據單元是字節
2) 字符流:以16位(即1char, 2byte, 16bit)做爲一個數據單元,數據流中最小的數據單元是字符, Java中的字符是Unicode編碼,一個字符佔用兩個字節。java
Java的IO主要包含兩個部分:web
Java io分類方式有不少,根據是否直接處理數據,Java io又分爲節點流和處理流,節點流是真正直接處理數據的;處理流是裝飾加工節點流的。面試
管道流:PipedInputStream,PipedOutputStream,PipedReader,PipedWrite,對管道進行處理的節點流。算法
處理流是對一個已存在的流的鏈接和封裝,經過所封裝的流的功能調用實現數據讀寫。如BufferedReader。處理流的構造方法老是要帶一個其餘的流對象作參數。
經常使用處理流(經過關閉處理流裏面的節點流來關閉處理流)api
數據流:DataInputStream,DataOutputStream,提供將基礎數據類型寫入到文件中,或者讀取出來。數組
下面是IO中輸入字節流的繼承關係。
InputStreamtomcat
ByteArrayInputStream
FileInputStream
FilterInputStream
* PushbackInputStream
* DataInputStream
* BufferedInputStream
LineNumberInputStream
ObjectInputStream
PipedInputStream
SequenceInputStream
StringBufferInputStream總結:
InputStream中的三個基本的讀方法
abstract int read() :讀取一個字節數據,並返回讀到的數據,若是返回-1,表示讀到了輸入流的末尾。
int read(byte[] b) :將數據讀入一個字節數組,同時返回實際讀取的字節數。若是返回-1,表示讀到了輸入流的末尾。
int read(byte[] b, int off, int len) :將數據讀入一個字節數組,同時返回實際讀取的字節數。若是返回-1,表示讀到了輸入流的末尾。off指定在數組b中存放數據的起始偏移位置;len指定讀取的最大字節數。網絡
下面是IO中輸出字節流的繼承關係。
OutputStreamdom
outputStream中的三個基本的寫方法
abstract void write(int b):往輸出流中寫入一個字節。
void write(byte[] b) :往輸出流中寫入數組b中的全部字節。
void write(byte[] b, int?off, int?len) :往輸出流中寫入數組b中從偏移量off開始的len個字節的數據。
其它重要方法:
java io的輸入和輸出是高度對應的,下圖表示字節流的輸入與輸出的對應關係。
上圖中藍色的爲主要的對應部分,紅色的部分是不對應部分。紫色的虛線部分表明這些流通常要搭配使用。
咱們主要看看這些字節流中不對稱的幾個類:
搭配使用的三對類:
ObjectInputStream/ObjectOutputStream和DataInputStream/DataOutputStream主要是要求寫對象/數據和讀對象/數據的次序要保持一致,不然可能不能獲得正確的數據,甚至拋出異常(通常會如此);PipedInputStream/PipedOutputStream在建立時通常就一塊兒建立,調用它們的讀寫方法時會檢查對方是否存在,或者關閉!
下面是IO中輸入字符流的繼承關係。
Reader
Reader基本的三個讀方法(和字節流對應):
(1) public int read() throws IOException; 讀取一個字符,返回值爲讀取的字符
(2) public int read(char cbuf[]) throws IOException; 讀取一系列字符到數組cbuf[]中,返回值爲實際讀取的字符的數量
(3) public abstract int read(char cbuf[],int off,int len) throws IOException; 讀取len個字符,從數組cbuf[]的下標off處開始存放,返回值爲實際讀取的字符數量,該方法必須由子類實現
下面是IO中輸出字符流的繼承關係。
Writer
writer的主要寫方法:
(1) public void write(int c) throws IOException; //寫單個字符
(2) public void write(char cbuf[]) throws IOException; //將字符數組cbuf[]寫到輸出流
(3) public abstract void write(char cbuf[],int off,int len) throws IOException; //將字符數組cbuf[]中的從索引爲off的位置處開始的len個字符寫入輸出流
(4) public void write(String str) throws IOException; //將字符串str中的字符寫入輸出流
(5) public void write(String str,int off,int len) throws IOException; //將字符串str 中從索引off開始處的len個字符寫入輸出流
可參照(字節流的輸入與輸出的對應)記憶
一、讀取鍵盤輸入,打印到控制檯
在刷題網站刷算法題的時候,在程序開頭都須要和鍵盤進行交互,用到的就是行奪取器BufferedReader和轉換流InputStreamReader。
public static void keyInAndPrintConsole() throws IOException { PrintWriter out = null; BufferedReader br = null; try{ System.out.println("請輸入:"); out = new PrintWriter(System.out, true); br = new BufferedReader(new InputStreamReader(System.in)); String line = null; while ((line = br.readLine()) != null) { if (line.equals("exit")) { System.exit(1); } out.println(line); } } catch (IOException e) { e.printStackTrace(); }finally{ out.close(); br.close(); } }
運行結果:
2 、用字節流讀寫文件
由於是用字節流來讀媒介,因此對應的是InputStream和OutputStream並且媒介對象是文件,因此用到子類是FileInputStream和FileOutputStream,這裏還能夠經過BufferedInputStream用緩衝流來讀取文件。
public static void readAndWriteByteToFile() throws IOException { InputStream is =null; OutputStream os = null; try { // 在try()中打開文件會在結尾自動關閉 is = new FileInputStream("D:/FileInputStreamTest.txt"); os = new FileOutputStream("D:/FileOutputStreamTest.txt"); byte[] buf = new byte[4]; int hasRead = 0; while ((hasRead = is.read(buf)) > 0) { os.write(buf, 0, hasRead); } System.out.println("write success"); } catch (Exception e) { e.printStackTrace(); }finally{ os.close(); is.close(); } }
運行結果:
三、用字符流進行讀寫操做
(1)FileReader和FileWriter
// 在try() 中打開的文件, JVM會自動關閉 public static void readAndWriteCharToFile() throws IOException{ Reader reader = null; Writer writer =null; try { File readFile = new File("d:/FileInputStreamTest.txt"); reader = new FileReader(readFile); File writeFile = new File("d:/FileOutputStreamTest.txt"); writer = new FileWriter(writeFile); char[] byteArray = new char[(int) readFile.length()]; int size = reader.read(byteArray); System.out.println("大小:" + size + "個字符;內容:" + new String(byteArray)); writer.write(byteArray); } catch (Exception e) { e.printStackTrace(); }finally{ reader.close(); writer.close(); } }
運行結果:
(2)StringReader和StringWriter
public static void stringNode() throws IOException { StringReader sr =null; StringWriter sw =null; try { String str = "學習不刻苦\n" + "不如賣紅薯;\n"; char[] buf = new char[32]; int hasRead = 0; // StringReader將以String字符串爲節點讀取數據 sr = new StringReader(str); while ((hasRead = sr.read(buf)) > 0) { System.out.print(new String(buf, 0, hasRead)); } // 因爲String是一個不可變類,所以建立StringWriter時,其實是以一個StringBuffer做爲輸出節點 sw = new StringWriter(); sw.write("黑夜給了我黑色的眼睛\n"); sw.write("我卻用它尋找光明\n"); // toString()返回sw節點內的數據 System.out.println(sw.toString()); } catch (Exception e) { e.printStackTrace(); }finally{ sw.close(); sr.close(); } }
運行結果:
四、字節流轉換爲字符流
在5.3中用字符流讀文件時,打印到控制檯的中文會亂碼,使用轉換流能夠解決這一問題
public static void convertByteToChar() throws IOException { InputStream is =null; Reader reader = null; try { File file = new File("d:/FileInputStreamTest.txt"); is = new FileInputStream(file); reader = new InputStreamReader(is,"gbk"); char[] byteArray = new char[(int) file.length()]; int size = reader.read(byteArray); System.out.println("大小:" + size + ";內容:" + new String(byteArray)); } catch (Exception e) { e.printStackTrace(); }finally{ reader.close(); is.close(); } }
運行結果:
五、隨機讀寫文件
使用RandomAccessFile能夠實現對文件的隨機讀取,主要是經過seek()方法實現指針偏移。
public static void randomAccessFileReadAndWrite() throws IOException { RandomAccessFile randomAccessFile =null; try { // 建立一個RandomAccessFile對象 randomAccessFile = new RandomAccessFile("d:/File.txt", "rw"); // 經過seek方法來移動指針 randomAccessFile.seek(10); // 獲取當前指針 long pointerBegin = randomAccessFile.getFilePointer(); // 從當前指針開始讀 byte[] contents = new byte[10]; randomAccessFile.read(contents); long pointerEnd = randomAccessFile.getFilePointer(); System.out.println("pointerBegin:" + pointerBegin + "\n" + "pointerEnd:" + pointerEnd + "\n" + new String(contents)); randomAccessFile.seek(20); // 獲取當前指針 long begin = randomAccessFile.getFilePointer(); randomAccessFile.write(contents); long end = randomAccessFile.getFilePointer(); System.out.println("begin:" + begin + "\n" + "end:" + end + "\n"); } catch (Exception e) { e.printStackTrace(); }finally{ randomAccessFile.close(); } }
運行結果:
操做前文件內容以下圖:
操做後控制檯打印信息:
操做後的文件內容:
六、讀寫管道
管道流要成對使用
public static void piped() throws IOException { final PipedOutputStream output = new PipedOutputStream(); final PipedInputStream input = new PipedInputStream(output); Thread thread1 = new Thread(new Runnable() { @Override public void run() { try { output.write("Hello world, pipe!".getBytes()); } catch (IOException e) { } } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { try { int data = input.read(); while (data != -1) { System.out.print((char) data); data = input.read(); } } catch (IOException e) { } finally { try { input.close(); } catch (IOException e) { e.printStackTrace(); } } } }); thread1.start(); thread2.start(); }
運行結果:
七、將多個輸入流當成一個輸入流依次讀取
public static void sequeue() throws IOException { FileInputStream fistream1 =null; FileInputStream fistream2 =null; SequenceInputStream sistream =null; FileOutputStream fostream =null; try { fistream1 = new FileInputStream("d:/A.txt"); fistream2 = new FileInputStream("d:/B.txt"); sistream = new SequenceInputStream(fistream1, fistream2); fostream = new FileOutputStream("d:/C.txt"); int temp; while( ( temp = sistream.read() ) != -1) { System.out.print( (char) temp ); fostream.write(temp); } } catch (Exception e) { e.printStackTrace(); }finally{ fostream.close(); sistream.close(); fistream1.close(); fistream2.close(); } }
運行結果:
八、推回輸入流使用實例
public static void pushback() throws FileNotFoundException, IOException { try (PushbackReader pr = new PushbackReader(new FileReader("D:/A.txt"), 64)) { char[] buf = new char[32]; String lastContent = ""; int hasRead = 0; while ((hasRead = pr.read(buf)) > 0) { String content = new String(buf, 0, hasRead); int targetIndex = 0; if ((targetIndex = (lastContent + content).indexOf("A")) > 0) { System.out.println(targetIndex); pr.unread((lastContent + content).toCharArray()); if (targetIndex > 32) { buf = new char[targetIndex]; } pr.read(buf, 0, targetIndex); System.out.println(new String(buf, 0, targetIndex)); System.out.println(new String(buf, targetIndex, buf.length-targetIndex)); System.exit(0); } else { System.out.println(lastContent); lastContent = content; } } } catch (IOException e) { e.printStackTrace(); } }
運行結果:
一、字節流和字符流的區別?
(1)讀寫單位不一樣:字節流以字節(8bit)爲單位,字符流以字符爲單位,根據碼錶映射字符,一次可能讀多個字節。
(2)處理對象不一樣:字節流能處理全部類型的數據(如圖片、avi等),而字符流只能處理字符類型的數據。
(3)字節流沒有緩衝區,是直接輸出的,而字符流是輸出到緩衝區的。所以在輸出時,字節流不調用colse()方法時,信息已經輸出了,而字符流只有在調用close()方法關閉緩衝區時,信息才輸出。要想字符流在未關閉時輸出信息,則須要手動調用flush()方法。
二、什麼是節點流,什麼是處理流,它們各有什麼用處,處理流的建立有什麼特徵?
見上文:節點流和處理流;
處理流的構造器必需要 傳入節點流的子類
三、把包括基本類型在內的數據和字符串按順序輸出到數據源,或者按照順序從數據源讀入,通常用哪兩個流?
DataInputStream DataOutputStream
四、什麼叫對象序列化,什麼是反序列化,實現對象序列化須要作哪些工做?
對象序列化:將對象以二進制的形式保存在硬盤上;
反序列化:將二進制的文件轉化爲對象讀取;
實現serializable接口能夠實現對象序列化,其中沒有須要實現的方法,implements Serializable只是爲了標註該對象是可被序列化的。
例如,在web開發中,若是對象被保存在了Session中,tomcat在重啓時要把Session對象序列化到硬盤,這個對象就必須實現Serializable接口。若是對象要通過分佈式系統進行網絡傳輸,被傳輸的對象就必須實現Serializable接口。
五、什麼是Filter流 有哪些?
FilterStream是一種IO流,主要做用是用來對存在的流增長一些額外的功能,像給目標文件增長源文件中不存在的行數,或者增長拷貝的性能等。在java.io包中主要由4個可用的filter Stream。兩個字節filter stream,兩個字符filter stream. 分別是FilterInputStream, FilterOutputStream, FilterReader and FilterWriter.這些類是抽象類,不能被實例化的。
Filter流的子類:
六、說說RandomAccessFile?
它在java.io包中是一個特殊的類,既不是輸入流也不是輸出流,它二者均可以作到。他是Object的直接子類。一般來講,一個流只有一個功能,要麼讀,要麼寫。可是RandomAccessFile既能夠讀文件,也能夠寫文件。 並且RandomAccessFile支持對文件的隨機訪問,實例可見上文:5.5隨機讀寫文件。
不少初學者剛剛學習java的IO時會比較茫然,確實IO類不少,不容易記憶,咱們能夠嘗試對其進行總結記憶,把流式部分歸納爲:兩個對應一個橋樑一個隨機。
兩個對應指:
1.字節流(Byte Stream)和字符流(Char Stream)的對應;
2.輸入和輸出的對應。
一個橋樑指:從字節流到字符流的橋樑。對應於輸入和輸出爲InputStreamReader和OutputStreamWriter;
一個隨機是:RandomAccessFile。能夠隨機讀取文件。
http://tool.oschina.net/apidocs/apidoc?api=jdk-zh https://blog.csdn.net/lgzaaron/article/details/52202443 https://blog.csdn.net/qq_25184739/article/details/51205186# https://www.2cto.com/kf/201704/524652.html https://blog.csdn.net/baobeisimple/article/details/1713797#t4 https://blog.csdn.net/lihuapiao/article/details/50731405 https://blog.csdn.net/zhuojiuyihu/article/details/7307567