Java之IO流詳解

大多數應用程序都須要實現與設備之間的數據傳輸,例如鍵盤能夠輸入數據,顯示器能夠顯示程序的運行結果等。在Java中,將這種經過不一樣輸入輸出設備(鍵盤,內存,顯示器,網絡等)之間的數據傳輸抽象表述爲」流」,程序容許經過流的方式與輸入輸出設備進行數據傳輸。Java中的」流」都位於java.io包中,稱爲IO(輸入輸出)流。java

IO流四你們族:數組

  • 1.InputStream:輸入字節流。
  • 2.OutputStream:輸出字節流。
  • 3.Reader:輸入字符流。
  • 4.Writer:輸出字符流。

其中一、2統稱字節流,三、4統稱字符流。接下來就來詳細介紹這四你們族流的用法。網絡

1.字節流

1.1概念

在計算機中,不管是文本、圖片、音頻、仍是視頻,全部的文件都是以二進制(字節)形式存在,IO流中針對字節的輸入輸出提供了一系列的流,統稱爲字節流。字節流是程序中最經常使用的流,根據數據的傳輸方向可將其分爲字節輸入流和字節輸出流。在JDK中,提供了兩個抽象類InputStream和OutputStream,它們是字節流的頂級父類,全部的字節輸入流都繼承自InputStream,全部的字節輸出流都繼承自OutputStream。學習

注意:以上所說的全部」輸入」、」輸出」都是相對於程序而言。數據經過輸入流從源設備輸入到程序,經過輸出流從程序輸出到目標設備,從而實現數據的傳輸。spa

1.2字節輸入流(InputStream)

經常使用方法:操作系統

  • int read();從輸入流讀取一個8位的字節,把它轉換成0~255之間的整數,並返回這一整數。
  • int read(byte[] b);從輸入流讀取若干字節,把它們保存到參數b指定的字節數組中,返回的整數表示讀取字節數。
  • int read(byte[] b,int off,int len);從輸入流讀取若干字節,把它們保存到參數b指定的字節數組中,off指定字節數組開始保存數據的起始下標,len表示讀取的字節數目。
  • void close();關閉此輸入流並釋放與該流關聯的全部系統資源。

前三個read()方法都是用來讀數據的,其中,第一個read()方法是從輸入流中逐個讀入字節,而第二個和第三個read()方法則將若干字節以字節數組的形式一次性讀入,從而提升讀數據的效率。在進行IO流操做時,當前IO流會佔用必定的內存,因爲系統資源寶貴,所以,在IO流操做結束後,應該調用close()方法關閉流,從而釋放當前IO流所佔的系統資源。視頻

Demo:讀取文件text.txt中的內容對象

1
2
3
4
5
6
7
8
9
10
11
12
import java.io.*;
public class Example{
	public static void main(String[] args){
		FileInputStream in=new FileInputStream("text.txt");
		int b;//定義一個int類型的變量,記住每次讀取的一個字節。
		while((b=in.read())!=-1)
		{
			System.out.prinln(b);//逐個打印出讀取的每個字節
		}
		in.close();
	}
}

 

1.3字節輸出流(OutputStream)

經常使用方法:繼承

  • void write(int b);向輸出流寫入一個字節。
  • void write(byte[] b);把參數b指定的字節數組的全部字節寫到輸出流。
  • void write(byte[] b,int off,int len);將指定byte數組中從偏移量off開始的len個字節寫入輸出流。
  • void flush();刷新此輸出流並強制寫出全部緩衝的輸出字節。
  • void close();關閉此輸出流並釋放與此流相關的全部系統資源。

前三個是重載的write()方法,都是用於向輸出流寫入字節,其中,第一個方法逐個寫入字節,後兩個方法是將若干個字節以字節數組的形式一次性寫入,從而提升寫數據的效率。flush()方法用來將當前輸出流緩衝區(一般是字節數組)中的數據強制寫入目標設備,此過程稱爲刷新。close()方法是用來關閉流並釋放與當前IO流相關的系統資源。圖片

Demo:將字符串(首先要將字符串轉換爲字節)寫入到文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.io.*;
public class Example{
	public static void main(String[] args){
		FileOutputStream out=new FileOutputStream(目標文件的路徑);
		String str="hello world";
		byte[] b=str.getBytes();//字符串調用getBytes()方法便可轉換成字節數組。
		for(int i=0;i<b.length;i++)
		{
			out.write(b[i]);
		}
		out.close();
	}
}

InputStream和OutputStream這兩個類雖然提供了一系列和讀寫數據有關的方法,可是這兩個類都是抽象類,不能被實例化。所以,針對不一樣的功能,兩者提供了不一樣的子類。

1.4代碼示例

下面這個例子經過對文件的複製來說解InputStream和OutputStream的用法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.io.*;
public class Example{
	 public static void main(String[] args){
	 	String fileName="/Users/codingBoy/Desktop/example1.jpg";//源文件路徑
	 	String fileName2="/Users/codingBoy/Desktop/example2.jpg";//目標文件路徑
	 	InputStream in=null;
	 	OutputStream out=null;
	 	try {
	 		in = new FileInputStream(fileName);
	 		out = new FileOutputStream(fileName2);
	 		int b;
	 		while ((b = in.read())!= -1) {
	 			out.write(b);
	 		}
		 }catch (Exception e)
		 {
		 	throw new RuntimeException(e);
 		 }finally {
		 	try {
		 		if (in != null) in.close();
				if (out!=null) out.close();
 			}catch (Exception e)
 			{
	 			throw new RuntimeException(e);
			}
 		}
    }
   }

 

1.5字節緩衝流

上面的例子實現了對文件的複製,可是一個字節一個字節的讀寫,須要頻繁的操做文件,效率很是低。爲了提升效率,須要使用兩個帶緩衝的字節流,分別是BufferedInputStream和BufferedOutputStream,它們兩個同時也屬於上文JavaWeb學習筆記之Jdbc二中講到的裝飾流。下面經過增長字節緩衝流來對上述例子進行變更:

Demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.io.*;
public class Example{
	 public static void main(String[] args){
		String fileName="/Users/codingBoy/Desktop/example1.jpg";//源文件路徑
	 	String fileName2="/Users/codingBoy/Desktop/example2.jpg";//目標文件路徑
	 	InputStream in=null;
	 	OutputStream out=null;
	 	BufferedInputStream bis=null;
	 	BufferedOutputStream bos=null;
	 	try {
	 		in = new FileInputStream(fileName);
	 		bis = new BufferedInputStream(in);//將輸入流對象做爲參數傳遞給輸入緩衝流
	 		out = new FileOutputStream(fileName2);
	 		bos = new BufferedOutputStream(out);
	 		
	 		int len;
	 		while((len=bis.read())!=-1)		 		{
	 			bos.write(len);
	 		}
	 	catch (Exception e)
		 {
		 	throw new RuntimeException(e);
 		 }finally {
		 	try {
		 		if (in != null) in.close();
		 		if (bis!=null) bis.close();
				if (out!=null) out.close();
				if (bos!=null) bos.close();
 			}catch (Exception e)
 			{
	 			throw new RuntimeException(e);
			}
 		}
    }
   }

 

2.字符流

2.1定義

前面咱們講過的InputStream和OutputStream類在讀寫文件時操做的都是字節,若是但願在程序中操做字符,使用這兩個類就不太方便,爲此JDK提供了字符流。同字節流同樣,字符流也有兩個抽象的頂級父類,分別是Reader和Writer。其中Reader是字符輸入流,用於從某個源設備讀取字符,Writer是字符輸出流,用於向某個目標設備寫入字符。其API跟字節流的相似。

2.2輸入字符流(Reader)

Demo:讀取reader.txt中的字符串

1
2
3
4
5
6
7
8
9
10
11
12
import java.io.*;
public class Example{
	 public static void main(String[] args){
	 	FileReader reader=new FileReader("reader.txt");
	 	int ch;
	 	while((ch=reader.read())!=-1)
	 	{
	 		System.out.println((char)ch);//經過read()方法讀取到的是int類型的值,因此須要進行強制轉換。
	 	}
	 	reader.close();
	 }
}

 

2.3輸出字符流(Writer)

Demo:將字符串輸出到目標文件中

1
2
3
4
5
6
7
8
9
10
import java.io.*;
public class Example{
	public static void main(String[] args){
		FileWrite out=new FileWrite(目標文件的路徑);
		String str="hello world";
		
		out.write(str);
		out.close();
	}
}

 

2.4字符緩衝流

字符流一樣提供了帶緩衝區的包裝流,分別是BufferedWriter和BufferedReader,其中BufferedReader用於對字符輸入流的包裝,BufferedWriter用於對字符輸出流的包裝。須要注意的是,在BufferedReader中有一個重要的方法readLine(),該方法用於一次讀取一行文本。接下來經過一個例子學習如何使用這兩個包裝流實現文件的複製。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.io.*;
public class Example{
	 public static void main(String[] args){
	 	String fileName="/Users/codingBoy/Desktop/example1.jpg";//源文件路徑
	 	String fileName2="/Users/codingBoy/Desktop/example2.jpg";//目標文件路徑
	 	Reader reader=null;
	 	BufferedReader bf=null;
	 	Writer writer=null;
	 	BufferedWriter bw=null;
	 	try {
	 		reader = new Reader(fileName);
	 		br=new BufferedReader(reader);
	 		writer = new Writer(fileName2);
	 		bw=new BufferedWriter(writer);
	 		String str;
	 		while ((str = bf.readLine())!= null) {
	 			bw.write(str);
	 			bw.newLine();//寫入一個換行符,該方法會根據不一樣的操做系統生成相應的換行符。
	 		}
		 }catch (Exception e)
		 {
		 	throw new RuntimeException(e);
 		 }finally {
		 	try {
		 		if (reader != null) reader.close();
		 		if (br !=null) br.close();
				if (writer!=null) writer.close();
				if (bw !=null) bw.close();
 			}catch (Exception e)
 			{
	 			throw new RuntimeException(e);
			}
 		}
    }
   }

3.轉換流

前面提到IO流可分爲字節流和字符流,有時字節流和字符流之間也須要進行轉換。在JDK中提供了兩個類能夠將字節流轉換爲字符流,它們分別是InputStreamReader和OutputStreamWriter。

轉換流也是一種包裝流,其中OutputStreamWriter是Writer的子類,它能夠將一個字節輸出流包裝成字符輸出流,方便直接寫入字符,而InputStreamReader是Reader的子類,它能夠將一個字節輸入流包裝成字符輸入流,方便直接讀取字符。

Demo:將字節流轉換爲字符流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.io.*;
public class Example{
	 public static void main(String[] args){
	 	String fileName="/Users/codingBoy/Desktop/example1.jpg";//源文件路徑
	 	String fileName2="/Users/codingBoy/Desktop/example2.jpg";//目標文件路徑
	 	InputStreamReader isr=new InputStreamReader(new FileInputStream(fileName1));
	 	BufferedReader br=new BufferedReader(isr);
	 	
	 	OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream(fileName2));
	 	BufferedWriter bw=new BufferedWriter(osw);
	 	
	 	String line;
	 	while((line=br.readLine())!=null)
	 	{
	 		bw.write(line);
	 	}
	 	
	 	br.close();
	 	bw.close();
	 }
}

 

4.其餘IO流

4.1ByteArrayInputStream和ByteArrayOutputStream

在前面的學習中,都是將文件直接存儲到硬盤,但有時候咱們但願將文件臨時存儲到緩衝區,方便之後讀取。爲此JDK中提供了一個ByteArrayOutputStream類。該類會在建立對象時就建立一個byte型數組的緩衝區,當向數組中寫數據時,該對象會把全部的數據先寫入緩衝區,最後一次行寫入文件。
Demo:將數據寫入緩衝區

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.io.*;
public class Example{
	 public static void main(String[] args){
	 	String fileName1="/Users/codingBoy/Desktop/example1.jpg";//源文件路徑
	 	String fileName2="/Users/codingBoy/Desktop/example2.jpg";//目標文件路徑
	 	FileInputStream in=new FileInputStream(fileName1);
	 	ByteArrayOutputStream bos=new ByteArrayOutputStream();
	 	FileOutputStream out=new FileOutputStream(fileName2);
	 	
	 	int b;
	 	while((b=in.read())!=-1)
	 	{
	 		bos.write(b);//先將數據寫入緩衝區,當須要寫入目標文件中的時候再調用輸出流的write(bos.toByteArray())方法。
	 	}
	 	
	 	in.close();
	 	bos.close();
	 	out.write(bos.toByteArray());
	 	out.close();
}

 

在該例中,定義了一個ByteArrayOutputStream對象,將從fileName1文件中讀取的字節所有寫入該對象的緩衝區,經過FileOutputStream對象將緩衝區的數據一次性寫入fileName2文件。

與ByteArrayOutputStream相似,ByteArrayInputStream是從緩衝區中讀取數據,接下來經過一個案例來演示ByteArrayInputStream如何讀取緩衝區的數據。

Demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.io.*;
public class Example{
	 public static void main(String[] args){
	 	byte[] bytes=new byte[]{97,98,99,100};
	 	ByteArrayInputStream bis=new ByteArrayInputStream(bytes);
	 	
	 	int b;
	 	while((b=bis.read())!=-1)
	 	{
	 		System.out.println((char)b);
	 	}
}
相關文章
相關標籤/搜索