一.流的分類java
1.java.io包中的類對應兩類流,一類流直接從指定的位置(如磁盤文件或內存區域)讀或寫,這類流稱爲結點流(node stream),其它的流則稱爲過濾器(filters)。過濾器輸入流每每是以其它輸入流做爲它的輸入源,通過過濾或處理後再以新的輸入流的形式提供給用戶,過濾器輸出流的原理也相似。node
2.Java的經常使用輸入、輸出流數組
java.io包中的stream類根據它們操做對象的類型是字符仍是字節可分爲兩大類:字符流和字節流。網絡
2.1Java的字節流:框架
InputStream是全部字節輸入流的祖先,而OutputStream是全部字節輸出流的祖先dom
2.2Java的字符流:jvm
Reader是全部讀取字符串輸入流的祖先,而writer是全部輸出字符串的祖先。函數
結合開始所說的輸入/輸出流 ,出現了個一小框架。性能
JAVA字節流:this
FileInputStream和FileOutputStream
這兩個類屬於結點流,第一個類的源端和第二個類的目的端都是磁盤文件,它們的構造方法容許經過文件的路徑名來構造相應的流。
FileInputStream infile = new FileInputStream("myfile.dat"); FileOutputStream outfile = new FileOutputStream("results.dat");
要注意的是:構造FileInputStream,,對應的文件必須存在而且是可讀的,而構造FileOutputStream時,如輸出文件已存在,則必須是可覆蓋的。
BufferedInputStream和BufferedOutputStream:
它們是過濾器流,其做用是提升輸入輸出的效率,對於FileInputStream當調用read()方法(每次讀取一個字節
)時都要從硬盤中獲取數據,對性能有必定影響,因此就須要使用緩衝流:從本身內存中的字節數組中讀取數據,默認一次讀8192個字節
DataInputStream和DataOutputStream:
這兩個類建立的對象分別被稱爲數據輸入流和數據輸出流。這是頗有用的兩個流,它們容許程序按與機器無關的風格讀寫Java數據。因此比較適合於網絡上的數據傳輸。這兩個流也是過濾器流,常以其它流如InputStream或OutputStream做爲它們的輸入或輸出。這兩種流失對流的擴展,能夠更加方便的讀取int,long,字符等類型的數據,好比:DataOutputStram:中增長了writeInt()/writeDouble()/writeUTF()方法
public class Main { public static void main(String[] args) throws IOException { String file="a.txt"; DataOutputStream dos=new DataOutputStream(new FileOutputStream(file)); dos.writeInt(10); dos.writeLong(10l); dos.writeUTF("中國");//採用UTF-8編碼寫入 dos.writeChars("中國");//採用utf-16be方式寫入 dos.close(); } }
RandomAccessFile的基本介紹和操做:
RandomAccessFile是Java提供的對文件內容的訪問,既能夠讀文件,也能夠寫文件,而且能夠隨機訪問文件,便可以訪問文件的任意位置,它在訪問文件時會有一個文件指針,在訪問過程當中會向後移動
File demo=new File("demo"); if(demo.exists()){ demo.mkdir();//若是文件夾不存在則建立 } File file=new File(demo,"a.txt");//以demo爲目錄建立a.txt文件 if(file.exists()){ file.createNewFile();//若是文件不存在則建立新的文件 } RandomAccessFile raf=new RandomAccessFile(file,"rw");//rw是文件模式中的可讀寫模式 System.out.println(raf.getFilePointer());//獲得指針的位置爲0 raf.write('A');//寫入'A'的後八位(每次只寫一個字節),指針後移一位 int i=15; raf.write(i>>>24);//寫入高八位 raf.write(i>>>16);.....每次寫一個字節,要寫四次 raf.writeInt(i);//直接寫入一個int類型數據 String s="中國"; byte[] gbk=s.getBytes("gbk"); raf.write(gbk); raf.seek(0);//讀文件 ,必須把指針移到頭部 byte[] buf=new byte[(int)raf.length()];//一次性讀取,把文件中的內容都讀到字節數組中去 raf.read(); System.out.println(Arrays.toString(buf));
字符流主要是用來處理字符的,Java採用16位的Unicode來表示字符串和字符,對應的字符流按輸入和輸出分別稱爲Reader和writer(一次處理一個字符,字符的底層仍然是基本的字節序列)
FileReader和FileWriter:
FileReader(讀文件類):
其直接父類就是InputStreamReader類
FileReader a=new FileReader("C:\\Users\\admin\\Desktop\1.txt");//注意:不能修改編碼集,即便用默認編碼集
FileWriter:
其直接父類爲OutputStreamWriter類
FileWriter a=new FileWrite("C:\\Users\\admin\\Desktop\1.txt",true);//加true參數表示在第二次寫入文件時是追加內容
InputStreamReader和OutputStreamWriter:
1.將字節流轉化爲字符流(解碼):
FileInputStream f==new FileInputStream("D:\\test.txt");; InputStreamReader f1=f1=new InputStreamReader(f,"UTF-8");//設置字符編碼爲UTF-8,默認項目的編碼爲gbk //讀取數據(一個字符一個字符的讀取): int c; while((c=f1.read())!=-1){ System.out.println((char)c); } //批量讀取(放入buffer這個字符數組,從0開始放置,最多放buffer.length個,返回的是讀到的字符個數): char[] buffer=new char[8*1024]; while((c==f1.read(buffer,0,buffer.length))!=-1){ String s=new String(buffer,0,c); }
2.將字符流轉化爲字節流(編碼):
FileOutputStream fos=new FileOutputStream("D:\\test.txt"); OutputStreamWriter osw=new OutputStreamWriter(fos,"UTF-8");
BufferedReader和BufferedWriter:
這兩個類對應的流使用了緩衝,能大大提升輸入輸出的效率,這兩個也是過濾器流,經常使用來對InputStreamReader和OutputStreamWriter進行處理,如:
public class Echo { public static void main(String[] args) throws IOException{ BufferedReader in =new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bw=new BufferedWriter(mew FileOutputStream("d:\\test.txt")); String s; while((s = in.readLine()).length() != 0){ System.out.println(s);//一次讀一行,並不能識別換行 bw.write(s); bw.newLine();//換行操做 bw.flush();//注意必定要添加這行代碼,才能寫入緩衝區中 } bf.close(); bw.close(); }
BuffferedReader和BufferedWriter之mark()
(方法標記流中的當前位置,調用reset()
將從新定位流)的使用:
public class Test{ public static void main(String[] args) throws IOException{ FileReader fr=new FileReader("D:\\test.txt"); BufferedReader br=new BufferedReader(fr,1000);//1000爲緩衝區大小 br.mark(1000);//參數要不小於緩衝區大小,字符流須要設置,而字節流的mark會默認在起始位置 第一種方式讀取: int c=0; c=br.read(); while(c!=-1){ System.out.println((char)c); c=br.read(); } 第二種方式讀取: br.reset();//再讀一次須要重置 String str=br.readLine(); while(str!=null) { System.out.println(str); str=br.readLine(); } }//注意關閉流最好在finally中進行 }
transient和ArrayList源碼解析:
private transient int age;//該元素不會進行jvm的默認序列化,但也能夠本身完成這個元素的序列化 ObjectOutputStream s; s.defaultWriteObject();//把jvm默認能序列化的元素進行序列化操做 s.writeInt(age);//本身完成age的序列化 ObjectInputStream s; s.defaultReadObject();//把jvm中默認能進行反序列化的元素進行反序列化 this.age=s.readInt();//本身完成age的反序列化操做
經過對ArrayList源碼列表的分析能夠知道,ArrayList中會對其中的有效元素進行序列化和反序列化以提升性能
序列化中子父類構造函數問題:
在序列化中若父類是實現了序列化接口,子類能夠不用實現序列化接口,能夠直接進行序列化,子類在序列化過程當中會遞歸的調用父類的構造方法
注意:對子類對象進行反序列化操做時,若是其父類沒有實現序列化接口,那麼其父類的構造函數會被顯示調用,不然就不會調用