什麼是IO流?
byte序列的讀寫,Java中的IO流是實現輸入/輸出的基礎.
1)
InputStream : 抽象類讀取數據的過程 包含讀取方法read();
in 模仿了讀取小說的過程html
簡單說 : in是讀取文件的java
OutputStream:抽象了寫出數據的過程 包含寫出方法write();
out模仿了寫筆記記錄的過程windows
簡單說 : out是寫入文件的數組
基本的byte流
InputStream(抽象方法read())
|--- FileInputStream(read()在文件上讀取) 節點流
|
|--- FilterInputStream 過濾器流,輸入流功能的擴展
| |--- DataInputStream(readInt()) 基本類型數據的讀取
| |--- BufferedInputStream 提供讀取緩衝區管理
| --- ObjectInputStream 過濾器流,依賴基本byte流,擴展對象的反序列化緩存
OutputStream(抽象方法write())
|--- FileOutputStream(write()在文件上寫實現寫入) 節點流
|
|--- FilterOutputStream 過濾器流,輸出流功能的擴
| |--- DataOutputStream(writerInt()) 基本類型數據的寫出
| |--- BufferedOutputStream 提供了輸出緩衝區管理
| --- ObjectOutputStream 過濾器流,依賴基本byte流,擴展對象的序列化tomcat
注意:除節點流外都是過濾器流服務器
字符流,能夠處理字符編碼,底層依賴於byte流
Reader 讀取文本
| --- InputStreamReader 過濾去,依賴基本byte輸入流
| 實現文本編碼的解析
|
| --- BufferedReader 過濾器, 須要依賴Reader 實例
| 提供了readLine()方法, 能夠在文本文件中讀取一行
| 是經常使用的文本讀取方法
Writer
| --- OutputStreamWriter 過濾器,,依賴基本byte輸出流
| 實現文本編碼
| --- PrintWriter 過濾器,依賴於Writer 流
| 提供了輸出文本常有方法println()ide
2) EOF = End of File = -1 (文件讀到末尾會返回-1)性能
3) 輸入流的基本方法
InputStream in = new InputStream(file) / /file是文件名
int b = in.read(); 讀取一個byte無符號填充到int底八位,-1是EOF
int.read(byte[] buf) 讀取數據填充到buf中
int.read(byte[] buf,int start,int size) 讀取數據填充到buf中
in.close 關閉輸入流編碼
4)輸出流的基本方法:
OutputStream out = new OutputStream(file) / /file是文件名
out.write(int b) 寫出一個byte 到流 b 的底八位寫出
out.write(byte[] buf) 將buf的一部分寫入流中
out.write(byte[] buf, int start, int size) 將buf的一部分寫入流中
out.flush() 清理緩存
out.close
1.FileInputStream (read()在文件上讀取) 節點流
方法: read() 從輸入流中讀取數據的下一個字節
read(byte[] buf) 從輸入流中讀取必定數量的字節,並將其存儲在緩衝區數組 buf中
read(byte[] b, int off, int len) 將輸入流中最多 len 個數據字節讀入 byte 數組。
例
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class InputStreamDemo { public static void main(String[] args) throws IOException { String file = "out.txt"; InputStream in = new FileInputStream(file); int b; while((b=in.read())!=-1){//read()方法 System.out.print(Integer.toHexString(b) + " "); } in.close(); in = new FileInputStream(file); //in.available() 能夠讀取的數據個數,小文件通常是文件長度 byte[] buf = new byte[in.available()]; in.read(buf);//read(byte[] buf)方法重載 in.close(); for (byte c : buf) { System.out.print(Integer.toHexString(c & 0xff) + " "); // c & 0xff --->將16進制寫成0xff的格式 //ffffffd6---> d6 //11111111 11111111 11111111 11010110 &對應相乘 //00000000 00000000 00000000 11111111 0xff //00000000 00000000 00000000 11010110 } } }
2 FileOutputStream(write()在文件上寫實現寫入) 節點流
方法 :write(int b) 將指定的字節寫入此輸出流。
write(byte[] buf) 將 b.length 個字節從指定的 byte 數組寫入此輸出流。
write(byte[] b, int off, int len) 將指定 byte 數組中從偏移量 off 開始的 len 個字節寫入此輸出流。
例子
import java.io.*; public class OutputStreamDemo { public static void main(String[] args) throws IOException{ String file = "out.txt"; OutputStream out = new FileOutputStream(file); out.write(65);//在文件中是以16進制存儲的,對應0x41 out.write(66);//0x42 byte[] buf = {(byte)0xd6,(byte)0xd0}; out.write(buf); out.flush();//刷出緩存,清理緩衝區,保證可靠寫 out.close(); } }
3.BufferedInputStream和BufferedOutputStream 的 用法
BufferedInputStream(FileInputStream in)
BufferedOutputStream(FileOutputStream out)
能夠提升性能
例子
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public class BufferedStreamDemo { public static void main(String[] args) throws IOException { //BufferedInputStream普通寫法 String file = "out.txt"; InputStream ins = new FileInputStream(file); BufferedInputStream bufin= new BufferedInputStream(ins); int b; while((b=bufin.read())!=-1){ System.out.println(Integer.toHexString(b)); } //經常使用寫法,只要用到FileInputStream的地方均可以套一個BufferedInputStream用來提高性能 BufferedInputStream in = new BufferedInputStream( new FileInputStream("out.txt")); //BufferedOutputStream BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream("out.txt")); out.write(65); } }
4.基本類型數據的寫出和讀入
DataOutputStream 方法:readInt() readLong() readBoolean()等
寫出(寫)
//例子 import java.io.*; public class DataOutDemo { public static void main(String[] args) throws IOException{ String file = "data.dat";//項目文件夾 OutputStream out = new FileOutputStream(file); //DataOutputStream 實現基本類型數據的序列化 //將基本類型數據拆開爲byte序列,寫入到out流中 DataOutputStream dos = new DataOutputStream(out); dos.write(-2); dos.writeInt(-2); dos.writeLong(-2); dos.writeByte(-2); dos.writeDouble(-2); dos.writeShort(-2); dos.writeFloat(-2); dos.writeBoolean(true); dos.writeChar('中'); dos.close(); } }
DataInputStream 方法: writeInt() writeChar() 等8種
讀入(讀)
import java.io.DataInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class DataInDemo { public static void main(String[] args) throws IOException{ String file = "data.dat"; InputStream in = new FileInputStream(file); //DataInputStream 從基本流中讀取基本類型數據,實現基本 //類型數據的反序列化 DataInputStream dis = new DataInputStream(in); int b = dis.read(); int i = dis.readInt(); long l= dis.readLong(); byte bx = dis.readByte(); double d = dis.readDouble(); short s = dis.readShort(); float f = dis.readFloat(); boolean bol = dis.readBoolean(); char c = dis.readChar(); dis.close(); System.out.print( b +" ");//254 fe System.out.print(i+" "); System.out.print(l+" "); System.out.print(bx+" "); System.out.print(d+" "); System.out.print(s+" "); System.out.print(f+" "); System.out.print(bol+" "); System.out.print(c+" "); } }
5 字符串的序列化(文字的編碼方案)
從char序列到byte序列 的轉換,叫"編碼"
1) String 字符串本質上是Char
2)utf-16be 編碼-----將16位char從中間切開爲2個byte
utf -16be是將 unicode char[] 序列化爲byte[]的編碼方案
可以支持65535個字符編碼,英文浪費空間
如:
char[] = ['A', 'B', '中']
對應 0041,0042,4e2d
utf-8:國際標準,是將unicode編碼爲byte序列的方案,採用變長編碼 1-N方案,其中英文1個byte,中文3個byte
unicoded的" 中": 4e 2d = 01001110 00101101
utf-8的"中":e4 b8 ad =11100100 10111000 10101101
1110xxxx 10xxxxxx 10xxxxxx
以0開頭的是英文(0-127)
110表示連續2字節表示一個字符
1110表示連續3字節表示一個字符
每一個數據字節以10開頭
GBK: 中國標準,支持20000+中日韓文,英文編碼1byte,中文2byte
與unicode不兼容,中文windows默認gbk
ISO8859-1:只支持255個英文字符,不支持中文(Sun服務器默認編碼,如tomcat等)
例子
import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class CharIODemo { public static void main(String[] args) throws IOException{ String str = "ABCD中國"; System.out.println(str); //Java 的字符是16位 Unicode值,而文件是8位Byte序列 //GBK System.out.println("GBK編碼方案,對字符編碼"); String file = "gbk.txt"; OutputStream out = new FileOutputStream(file);//默認GBK編碼方案 byte[] gbk = str.getBytes("GBK"); out.write(gbk); out.close(); IOUtils.print(file); //UTF-16BE,每一個編碼是2個字節 System.out.println("UTF-16BE編碼方案,對字符編碼"); file = "utf-16be.txt"; out = new FileOutputStream(file); byte[] utf16be = str.getBytes("UTF-16BE"); out.write(utf16be); out.close(); IOUtils.print(file); //UTF-8,英文是1個字節,中文是3個字節 System.out.println("UTF-8編碼方案,對字符編碼"); file = "utf-8.txt"; out = new FileOutputStream(file); byte[] utf8 = str.getBytes("UTF-8");//編碼string -> byte[] out.write(utf8); out.close(); IOUtils.print(file); byte[] buf = IOUtils.read("utf-8.txt"); //new String(buf,"UTF-8"),構造器能夠將 byte編碼序列 //解碼爲 char序列(字符串) String s = new String(buf,"UTF-8");//解碼byte-> String System.out.println(s); } }
6 字符流IO(Reader Writer)
1) 字符的處理,一次處理一個字符(unicode編碼)
2) 字符的底層仍然是基本的字節流
3) 字符流的基本實現
InputStreamReader 完成byte流解析爲char流,按照編碼解析
OutputStreamWriter 提供char流到byte流,按照編碼處理
4) 字符流的過濾器
是字符讀寫的功能擴展,極大的方便了文本的讀寫操做
BufferedReader : readLine() 一次讀取一行
PrintWriter : println() 一次打印一行
5)讀取一個文本文件
InputStream is = new FileInputStream("test.txt");
Reader in = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(in);
或者
BufferedReader in = new BufferedReader(new FileReader(filename));
例子:
import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; public class TestReaderDemo { public static void main(String[] args) throws IOException{ //Scanner BufferedReader都是流的功能擴展,是過濾器 // 不能單獨使用,最終須要依賴於基本byte流(in) //Scanner 提供了nextLine()方法//Java5之後 //BufferedReader 提供了 readLine()方法,讀取一行 //readLine()讀取到文件末尾返回null //逐行讀取文本文件,顯示到系統控制檯 //工做中經常使用 String file = "in.txt"; //爲當前工做區workspace/項目名/in.txt BufferedReader in = new BufferedReader( new InputStreamReader( new BufferedInputStream( new FileInputStream(file)),"gbk")); String str; while((str = in.readLine()) != null){ System.out.println(str); } in.close(); }
6)寫出一個文本文件
PrintWriter out = new PrintWriter(new FileWriter(new FileOutputStream(filename)));
或者
PrintWriter out = new PrintWriter(
new OutputStreamWriter(
new FileOutputStream(filename)))
例子
import java.io.IOException; import java.io.PrintWriter; import java.util.Scanner; public class SyncWriteDemo { public static void main(String[] args) throws IOException{ Scanner in = new Scanner(System.in); String file = "sync.txt"; PrintWriter out = new PrintWriter(file,"UTF-8"); while(true){ String str = in.nextLine(); out.println(str); if("q".equalsIgnoreCase(str)){ break; } } out.close(); } }
7)系統的默認編碼,中文通常是GBK
如何查看默認編碼?
String encoding = System.getProperty("file.encoding");
7 對象的IO序列化和深層複製
什麼是對象序列化:
將對象Object轉換爲byte序列,反之叫作對象的反序列華
1)序列化流,是過濾流
ObjectOutputStream 方法 writeObject() 對象的序列化
ObjectInputStream 方法readObject() 對象的反序列化
2)序列化接口(Serializable)
對象必須實現"序列化接口Serializable"才能進行序列化,不然將出現不能序列化的異常
Serializable是一個空的接口,沒有任何方法 ,僅做爲序列化的一個標識
3)JavaBean 規範規定,Java類必須實現Serializable接口
Java API中的類大可能是符合Java Bean規範的,基本都實現了Serializable
4) 對象的序列化能夠變相實現對象的深層複製
例子
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class ObjectIODemo { public static void main(String[] args) throws Exception{ String file = "obj.dat"; ObjectOutputStream out = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream(file))); Foo foo =new Foo(); out.writeObject(foo);//將foo引用的對象,序列化到文件中 out.close(); //讀出 ObjectInputStream in = new ObjectInputStream( new BufferedInputStream( new FileInputStream(file))); Foo foo1 = (Foo)in.readObject();//對象反序列化 in.close(); System.out.println(foo1.name); System.out.println("深層複製:對象被複制,對象屬性也被複制"); System.out.println(foo==foo1);//false 對象複製了(一層) System.out.println(foo.name == foo1.name);//false ,屬性被複制了(二層) //利用序列化 和 反序列化 能夠簡潔的實現 對象的深層複製 } } class Foo implements Serializable{//Serializable沒有聲明方法 String name = "Tom"; }
淺層複製與深層複製
1)java的默認規則是淺層複製,性能好,但隔離性差,如(clone(),Arrays.copyOf)
淺層複製 : 對象的引用不一樣,但對象中屬性的引用相同
2)利用序列化能夠實現深層複製
深層複製: 對象的引用不一樣,但對象中的屬性的引用也不相同
例
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class DeepcopyDemo { public static Object deepCope(Object obj){ try{ //1. 對象序列化 // 緩衝流: 字節數組輸出流 ByteArrayOutputStream buf = new ByteArrayOutputStream(); //對象輸出流 ObjectOutputStream out = new ObjectOutputStream( new ByteArrayOutputStream()); out.writeObject(obj);//序列化對象到buf中 out.close(); //2 .對象的反序列化 byte[] ary = buf.toByteArray(); ByteArrayInputStream bais = new ByteArrayInputStream(ary); ObjectInputStream in = new ObjectInputStream(bais); Object o = in.readObject();//從ary反序列化 in.close(); return o; }catch(Exception e){ e.printStackTrace(); throw new RuntimeException(e); } } }
以上用到的ByteArrayInputStream和ByteArrayOutputStream
下面有一個ByteArrayInputStream和ByteArrayOutputStream的例子
例子
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Arrays; import com.tarena.day18.IOUtils; public class ByteArrayIODemo { public static void main(String[] args) throws IOException{ byte[] ary = {1,-1,127,-128}; // {00000001, 11111111, 01111111, 10000000} ByteArrayInputStream in = new ByteArrayInputStream(ary); int b = in.read();//1 00000000 00000000 00000000 00000001 System.out.println(b); b = in.read(); System.out.println(b);//255 00000000 00000000 00000000 11111111 b = in.read(); System.out.println(b);//127 00000000 00000000 00000000 01111111 b = in.read(); System.out.println(b);//128 00000000 00000000 00000000 10000000 b = in.read(); System.out.println(b);//-1 11111111 11111111 11111111 11111111 in.close(); ByteArrayOutputStream out = new ByteArrayOutputStream();//默認開闢32byte的數組做爲輸出目標 //若是滿了就自動擴容 //out:[0,0,0,0,0,0,0,.....] // out.write(1);//[1,0,0,0,0,0,....] out.write(-2);//[1,fe,0,0,0,0,0,....] out.write(-1);//[1,fe,ff,0,0,0,0,....] out.close(); byte[] buf = out.toByteArray();//複製有效部分 IOUtils.print(buf);//[01, fe, ff ] } }
原文:http://www.cnblogs.com/hqr9313/archive/2012/04/23/2467294.html