Writer的子類,既能夠接收字符流,也能夠接收字節流,還能夠接收文件名或者文件對象,很是方便java
同時,還能夠設置自動刷新以及保持原有格式寫入各類文本類型的print方法windows
1: //讀取鍵盤錄入,打印大寫
2: private static void printWriterMethod() throws IOException
3: {
4: BufferedReader bufr =
5: new BufferedReader(new InputStreamReader(System.in));
6:
7: PrintWriter out = new PrintWriter(System.out,true);
8:
9: String line = null;
10:
11: while( (line = bufr.readLine()) != null)
12: {
13: if("over".equals(line))
14: break;
15: //只需一條語句,即可打印一行數據,很是方便
16: out.println(line.toUpperCase());
17: }
18:
19: out.close();
20: bufr.close();
21: }
序列流,可將多個流合併成一個流,按序列進行讀取數組
可手動指定各個流建立對象,也可將多個流存入集合,利用枚舉Enumeration來建立對象安全
1: import java.io.*;
2: import java.util.*;
3:
4: class SequenceInputStreamDemo
5: {
6: public static void main(String[] args) throws IOException
7: {
8:
9: int num = splitFile(new File("pic.jpg"));
10:
11: /*
12: 合併分割後的流
13: */
14:
15: //定義Vector集合存儲全部part文件的字節輸入流
16: Vector<FileInputStream> v = new Vector<FileInputStream>();
17:
18: for(int i = 1 ; i <= num ; i ++ )
19: {
20: v.add(new FileInputStream(i+".part"));
21: }
22:
23: Enumeration<FileInputStream> en = v.elements();
24:
25: FileOutputStream fos = new FileOutputStream("pic1.jpg");
26:
27: //定義序列流,經過枚舉合併全部的輸入流
28: SequenceInputStream sis = new SequenceInputStream(en);
29:
30: byte[] buf = new byte[1024];
31:
32: int len = -1;
33:
34: while( (len = sis.read(buf)) != -1)
35: {
36: //將合併後的流寫入一個文件
37: fos.write(buf,0,len);
38: }
39:
40: fos.close();
41: sis.close();
42: }
43:
44: //分割流
45: private static int splitFile(File f) throws IOException
46: {
47: FileInputStream fis = new FileInputStream(f);
48:
49: long size = f.length();
50:
51: byte[] buf = null;
52:
53: //選擇緩衝區大小
54: if(size > 1024*1024*5)
55: buf = new byte[1024*1024];
56: else
57: buf = new byte[(int)size/5];
58:
59: int len = -1;
60: int count = 1;
61:
62: while( (len = fis.read(buf)) != -1)
63: {
64: //每一個緩衝區的內容分別寫入不一樣的part文件
65: FileOutputStream fos = new FileOutputStream((count++)+".part");
66: fos.write(buf,0,len);
67: fos.close();
68: }
69:
70: fis.close();
71:
72: return count-1;
73: }
74: }
ObjectInputStream,ObjectOutputStream多線程
將對象存取在硬盤上,叫作對象的持久化存儲(存儲的是對象的屬性值,而不是方法)app
想要對對象進行序列化,該對象必須實現Serializable接口,Serializable接口沒有方法,稱爲標記接口,實現過程只是給實現者加入一個序列化的ID:ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L; 其實就是序列號,這個序列號是由變量的聲明語句自動生成的,咱們也能夠本身定義類的序列號dom
1: import java.io.*;
2:
3: class Person implements Serializable
4: {
5: //序列號,保證類型一致
6: static final long serialVersionUID = 42L;
7:
8: //靜態變量以及transient修飾的變量不會被序列化
9: static String country = "cn";
10: transient int grade;
11: private String name;
12: private int age;
13:
14: Person(String name,int age,int grade,String country)
15: {
16: this.name = name;
17: this.age = age;
18: this.grade = grade;
19: this.country = country;
20: }
21:
22: public String toString()
23: {
24: return name+"::"+age+"::"+grade+"::"+country;
25: }
26: }
27:
28: class ObjectStreamDemo
29: {
30: public static void main(String[] args) throws Exception
31: {
32:
33: //writeObj();
34: readObj();
35: }
36:
37: //將對象寫入流中
38: private static void writeObj() throws IOException
39: {
40: ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
41:
42: oos.writeObject(new Person("Shawn",30,3,"en"));
43: oos.writeObject(new Person("feng",23,6,"usa"));
44:
45: oos.close();
46: }
47:
48: //將對象從流中讀出並打印
49: private static void readObj() throws Exception
50: {
51: ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
52:
53: Person p1 = (Person)ois.readObject();
54: Person p2 = (Person)ois.readObject();
55:
56: System.out.println("p1 --- "+p1);
57: System.out.println("p2 --- "+p2);
58:
59: ois.close();
60: }
61: }
咱們能夠看到,靜態變量和transient修飾的變量是不會被序列化到硬盤上的this
PipedInputStream,PipedOutputStream編碼
1: import java.io.*;
2:
3: //讀管道流線程
4: class Read implements Runnable
5: {
6: private PipedInputStream pis;
7:
8: Read(PipedInputStream pis)
9: {
10: this.pis = pis;
11: }
12:
13: public void run()
14: {
15: try
16: {
17: byte[] buf = new byte[1024];
18:
19: int len = -1;
20:
21: //阻塞方法,讀不到數據會等待
22: len = pis.read(buf);
23:
24: System.out.println(new String(buf,0,len));
25:
26: pis.close();
27: }
28: catch (IOException e)
29: {
30: System.out.println("pipe read error!");
31: }
32:
33: }
34: }
35:
36: //寫管道流線程
37: class Write implements Runnable
38: {
39: private PipedOutputStream pos;
40:
41: Write(PipedOutputStream pos)
42: {
43: this.pos = pos;
44: }
45:
46: public void run()
47: {
48: try
49: {
50: pos.write("pipe is coming!".getBytes());
51:
52: pos.close();
53: }
54: catch (IOException e)
55: {
56: System.out.println("pipe write error!");
57: }
58:
59: }
60: }
61:
62: class PipedStreamDemo
63: {
64: public static void main(String[] args) throws IOException
65: {
66: PipedInputStream pis = new PipedInputStream();
67: PipedOutputStream pos = new PipedOutputStream();
68:
69: //連接讀寫管道
70: pis.connect(pos);
71:
72: new Thread(new Read(pis)).start();
73:
74: new Thread(new Write(pos)).start();
75: }
76: }
RandomAccessFilespa
直接繼承Object類,內部封裝了字節輸入輸出流,同時封裝了文件的指針,可對基本數據類型進行直接讀寫,最大的好處是能夠實現數據的分段寫入,經過seek方法。
用隨機訪問實現的多線程複製文件(後期會改進代碼,完成多線程下載)
1: import java.io.*;
2:
3: //下載線程
4: class DownLoadThread implements Runnable
5: {
6: private RandomAccessFile in;
7: private RandomAccessFile out;
8: private int offset;//偏移量
9: private int buf_size;//分配數據量
10: private int block_size;//緩衝區大小
11:
12: //初始化
13: DownLoadThread(RandomAccessFile in,RandomAccessFile out,int offset,int buf_size)
14: {
15: this.in = in;
16: this.out = out;
17: this.offset = offset;
18: this.buf_size = buf_size;
19:
20: block_size = 1024*512;
21: if(buf_size < block_size)
22: block_size = buf_size;
23:
24: }
25:
26: public void run()
27: {
28: try
29: {
30: System.out.println(Thread.currentThread().getName()+"開始下載...");
31:
32: //讀寫流都偏移到指定位置
33: in.seek(offset);
34: out.seek(offset);
35:
36: byte[] buf = new byte[block_size];
37:
38: int len = -1;
39:
40: int lastSize = buf_size;
41:
42: //讀取信息並寫入到目的地
43: while( (len = in.read(buf)) != -1)
44: {
45: out.write(buf,0,len);
46:
47: lastSize -= len;
48:
49: //分配數據量完成,結束線程
50: if(lastSize == 0)
51: break;
52: if(lastSize < block_size)
53: {
54: block_size = lastSize;
55: buf = new byte[block_size];
56: }
57: }
58:
59: System.out.println(Thread.currentThread().getName()+"下載完成!");
60:
61: in.close();
62: out.close();
63:
64: }
65: catch (IOException e)
66: {
67: throw new RuntimeException(e);
68: }
69:
70: }
71: }
72:
73: class MutiDownLoadDemo
74: {
75: public static void main(String[] args) throws Exception
76: {
77: //肯定源文件和目的文件
78: File fin = new File("1.avi");
79: File fout = new File("5.avi");
80:
81:
82: multiDownload(fin,fout,12);
83:
84:
85: }
86:
87: //多線程下載 thread_num爲線程數
88: private static void multiDownload(File fin,File fout,int thread_num) throws Exception
89: {
90: RandomAccessFile in = new RandomAccessFile(fin,"r");
91:
92: RandomAccessFile out = new RandomAccessFile(fout,"rwd");
93:
94: int len = (int)fin.length();
95:
96: //肯定目的文件大小
97: out.setLength(len);
98:
99: in.close();
100: out.close();
101:
102: System.out.println("-----------File size : "+(len>>20)+" MB--------------");
103: System.out.println("-----------Thread num: "+thread_num+"---------");
104:
105: //肯定每一個線程分配的數據量
106: int buf_size = len/thread_num;
107:
108: System.out.println("-----------buffer size: "+(buf_size>>20)+" MB-----------");
109:
110: //開啓每一個線程
111: for(int i = 0 ; i < thread_num ; i ++)
112: {
113: //"rwd"模式表明可讀可寫而且線程安全
114: new Thread(
115: new DownLoadThread(new RandomAccessFile(fin,"r"),new RandomAccessFile(fout,"rwd"),i*buf_size,buf_size)
116: ).start();
117: }
118: }
119: }
DataInputStream,DataOutputStream
1: public static void main(String[] args) throws IOException
2: {
3: DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
4:
5: dos.writeInt(123);
6:
7: dos.writeDouble(123.45);
8:
9: dos.writeBoolean(true);
10:
11: DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
12:
13: System.out.println(dis.readInt());
14: System.out.println(dis.readDouble());
15: System.out.println(dis.readBoolean());
16: }
ByteArrayInputStream與ByteArrayOutputStream
CharArrayReader與CharArrayWrite
StringReader 與 StringWriter
字符流出現是爲了更方便的操做字符,經過InputStreamReader和OutputStreamWriter能夠任意指定編碼表進行解碼轉換
計算機開始只能識別二進制數據,爲了更方便的表示各個國家的文字,就將各個國家的文字與二進制數據進行一一對應,造成了一張表,即爲編碼表
ASCII:美國標準信息交換碼。
用一個字節的7位能夠表示。
ISO8859-1:拉丁碼錶。歐洲碼錶
用一個字節的8位表示。
GB2312:中國的中文編碼表。
GBK:中國的中文編碼表升級,融合了更多的中文文字符號。
Unicode:國際標準碼,融合了多種文字。
全部文字都用兩個字節來表示,Java語言使用的就是unicode
UTF-8:最多用三個字節來表示一個字符
......
只有GBK和UTF-8識別中文,GBK向下兼容GB2312
GBK兩個字節表示一個字符,UTF-8是1-3個字節表示一個字符,每一個字節前面1-3位做爲標識頭
GBK和UTF-8都兼容ASCII碼錶
1: public static void main(String[] args) throws Exception
2: {
3: //字符串
4: String s = "你好";
5:
6: //用UTF-8編碼表編碼s字符串
7: byte[] b = s.getBytes("UTF-8");
8:
9:
10: System.out.println(Arrays.toString(b));
11:
12: //用GBK編碼表解碼
13: String s1 = new String(b,"GBK");
14:
15: //獲取以後發現不是原來的字符串
16: System.out.println(s1);
17:
18: //用GBK從新編碼回去
19: byte[] b1 = s1.getBytes("GBK");
20:
21: //再用UTF-8解碼
22: String s2 = new String(b1,"UTF-8");
23:
24: System.out.println(s2);
25:
26:
27: }
這樣作存在一個問題,因爲GBK與UTF-8都支持中文,因此UTF-8編解碼時有可能會去內部的類似碼錶去查找,這樣編碼出來的字符就會與原字符不符,因此通常使用ISO8859-1與中文碼錶互相編解碼轉換
新建一個文本文檔,寫入「聯通」兩個字,保存,關閉,再打開,發現變成了一個奇怪的字符,這是爲何呢?
首先windows默認的是ANSI編碼,而UTF-8編碼的標識頭規則以下圖
因爲記事本是由編碼自己的規律判斷選取哪一個編碼表的
因此答案是,「聯通」這兩個字由ANSI編碼以後的碼流符合UTF-8的規則,則記事本自動識別是UTF-8的字符,而去查了UTF-8的碼錶
解決方法,咱們只要在聯通前面加上任意字符,記事本就不會誤判爲UTF-8解碼了