Java之字節流、字節緩衝流

在上一個剛剛介紹了File類,創建了文件或者文件夾,但是裏面的數據是怎麼操作它呢,若想操作文件中的數據,需要藉助字節流或者字符流。

字節流

字節流是由字節組成的,字符流是由字符組成的.

IO流的分類

- 字節流

    - 字節輸入流 InputStream 抽象類

        -  FileInputStream 操作文件的字節輸入流

    - 字節輸出流 OuputStream抽象類

        -FileOutputStream 操作文件的字節輸出流

- 字符流

    - 字符輸入流 Reader抽象類

        - InputStreamReader 輸入操作的轉換流

            - FileReader 用來操作文件的字符輸入流(簡便的流)

    - 字符輸出流 Writer抽象類

        - OutputStreamWriter 輸出操作的轉換流

            - FileWriter 用來操作文件的字符輸出流(簡便的流)


字節輸出流OutputStream

OuputStream是一個抽象類,表示輸出字節流的所有類的超類,操作的數據都是字節,字節流處理單元爲一個字節。

使用OuputStream該抽象類的子類如FileOutputStream、ObjectOutputStream.

字節輸出流中定義的方法主要爲write方法,如:

void write(byte[] b);//將b.length個字節從指定的byte數組寫入此輸出流。
void write(byte[] b,int off,int len);//將指定的byte數組中從偏移量off開始的冷個字節寫入此輸出流。
abstract void write(int b);//將指定的字節寫入此輸出流。

FileOutputStream類

即文件輸出流,是用於將數據寫入 File的輸出流。

構造方法

FileOutputStream(File file);//創建一個向指定File對象表示的文件中寫入數據的文件輸出流
FileOutputStream(String name);//創建一個向指定路徑名字符串表示的文件中寫入數據的文件輸出流


實例-寫入數據到文件中:

public class FileOutputStreamDemo {
	public static void main(String[] args) throws IOException {
		//需求:將數據寫入到文件中。
		//創建存儲數據的文件。
		File file = new File("c:\\file.txt");
		//創建一個用於操作文件的字節輸出流對象。一創建就必須明確數據存儲目的地。
		//輸出流目的是文件,會自動創建。如果文件存在,則覆蓋。
		FileOutputStream fos = new FileOutputStream(file);//使用傳入File對象的構造方法
		//調用父類中的write方法。
		byte[] data = "abcde".getBytes();//使用String類中的getBytes方法將String對象變爲Byte數組
		fos.write(data);
		//關閉流資源。
		fos.close();
	}
}


IO異常處理

在實際開發中,創建一個文件並向該文件內寫入數據,並關掉,可能會發生異常。實例代碼

public class FileOutputStreamDemo3 {
	public static void main(String[] args) {
		File file = new File("c:\\file.txt");
		//定義FileOutputStream的引用
		FileOutputStream fos = null;
		try {
			//創建FileOutputStream對象
			fos = new FileOutputStream(file);
			//寫出數據
			fos.write("abcde".getBytes());
		} catch (IOException e) {
			System.out.println(e.toString() + "----");
		} finally {
			//一定要判斷fos是否爲null,只有不爲null時,纔可以關閉資源
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					throw new RuntimeException("");
				}
			}
		}
	}
}

字節輸入流InputStream

特點是從內存將文件中的數據讀出,InputStream可以實現,該類仍爲抽象類,是表示字節數入流的所有類的超類,使用它的子類如:FileInputStream,ObjectInputStream。

FileInputStream從文件系統中的某個文件中獲得輸入字節,

FileInputStream類的構造方法

FileInputStream(File file)  通過打開一個到實際文件的連接來創建一個 FileInputStream,該文件通過文件系統中的 File 對象 file 指定。

FileInputStream(String name)   通過打開一個到實際文件的連接來創建一個 FileInputStream,該文件通過文件系統中的路徑名 name 指定。


FileInputStream主要方法

int read();//從輸入流中讀取的下一個字節,一次只能讀一個字節。
int read(byte[] b);//從輸入流中讀取一定數量的字節,並將其存儲在緩衝區數組 b 中。
int read(byte[] b,int off,int len);//將輸入流中最多 len 個數據字節讀入 byte 數組。
1.使用read()方法實例:

public class FileInputStreamDemo {
	public static void main(String[] args) throws IOException {
		File file = new File("c:\\file.txt");
		//創建一個字節輸入流對象,必須明確數據源,其實就是創建字節讀取流和數據源相關聯。
		FileInputStream fis = new FileInputStream(file);
		//讀取數據。使用 read();一次讀一個字節。
		int ch = 0;
		while((ch=fis.read())!=-1){
			System.out.println("ch="+(char)ch);
                }
		// 關閉資源。
		fis.close();
	}
}
此方法缺點在於讀取大文件時,速度太慢。

2. 使用read(byte[ ])方法實例:

public class FileInputStreamDemo2 {
	public static void main(String[] args) throws IOException {
		/*
		 * 演示第二個讀取方法, read(byte[]);
		 */
		File file = new File("c:\\file.txt");
		// 創建一個字節輸入流對象,必須明確數據源,其實就是創建字節讀取流和數據源相關聯。
		FileInputStream fis = new FileInputStream(file);		
		//創建一個字節數組。
		byte[] buf = new byte[1024];//長度可以定義成1024的整數倍。		
		int len = 0;
		while((len=fis.read(buf))!=-1){
			System.out.println(new String(buf,0,len));
		}
		fis.close();
	}
}
讀取是通過創建一個字節數組,讀取一個字節數組的大小再寫入程序中,此方法的優勢在於速度快。


3. 使用字節緩衝輸入流BufferedInputStream實例:

/*
	 * 從文件中讀取數據
	 * 1,創建緩衝流對象
	 * 2,讀數據,打印
	 * 3,關閉
	 */
	private static void read() throws IOException {
		//1,創建緩衝流對象
		FileInputStream fileIn = new FileInputStream("abc.txt");
		//把基本的流包裝成高效的流
		BufferedInputStream in = new BufferedInputStream(fileIn);
		//2,讀數據
		int ch = -1;
		while ( (ch = in.read()) != -1 ) {
			//打印
			System.out.print((char)ch);
		}
		//3,關閉
		in.close();
	}


使用字節流實現複製文件


原理是讀取一個已有的數據,並將這些數據寫入到另一個文件中。


public class CopyFileTest {
	public static void main(String[] args) throws IOException {
		//1,明確源和目的。
		File srcFile = new File("c:\\YesDir\test.JPG");
		File destFile = new File("copyTest.JPG");
		
		//2,明確字節流 輸入流和源相關聯,輸出流和目的關聯。
		FileInputStream fis = new FileInputStream(srcFile);
		FileOutputStream fos = new FileOutputStream(destFile);
		
		//3, 使用輸入流的讀取方法讀取字節,並將字節寫入到目的中。
		int ch = 0;
		while((ch=fis.read())!=-1){
			fos.write(ch);
		}
		//4,關閉資源。
		fos.close();
		fis.close();
	}
}

上述代碼輸入流和輸出流之間是通過ch這個變量進行數據交換的。

上述複製文件有個問題,每次都從源文件讀取一個,然後在寫到指定文件,接着再讀取一個字符,然後再寫一個,一直這樣下去。效率極低。


使用緩衝數組方式複製文件

public class CopyFileByBufferTest {
	public static void main(String[] args) throws IOException {
		File srcFile = new File("c:\\YesDir\test.JPG");
		File destFile = new File("copyTest.JPG");
		// 明確字節流 輸入流和源相關聯,輸出流和目的關聯。
		FileInputStream fis = new FileInputStream(srcFile);
		FileOutputStream fos = new FileOutputStream(destFile);
		//定義一個緩衝區。
		byte[] buf = new byte[1024];
		int len = 0;
		while ((len = fis.read(buf)) != -1) {
			fos.write(buf, 0, len);// 將數組中的指定長度的數據寫入到輸出流中。
		}
		// 關閉資源。
		fos.close();
		fis.close();
	}
}


字節緩衝流

在進行過讀取文件中數據的操作,讀取數據量大的文件時,讀取的速度會很慢,很影響我們程序的效率,Java中提高了一套緩衝流,它的存在,可提高IO流的讀寫速度。

緩衝流,根據流的分類分類字節緩衝流與字符緩衝流。

字節緩衝流:

1. 字節緩衝輸出流 BufferedOutputStream

2. 字節緩衝輸入流 BufferedInputStream

它們的內部都包含了一個緩衝區,通過緩衝區讀寫,就可以提高了IO流的讀寫速度

1. 字節緩衝輸出流 BufferedOutputStream

構造方法:

BufferedOutputStream(OutputStream out);//創建一個新的緩衝輸出流,以將數據寫入指定的底層輸出流。
BufferedOutputStream(OutputStream out,int size);//創建一個新的緩衝輸出流,以將具有指定緩衝區大小的數據寫入指定的底層輸出流。
其參數爲:字節輸出流的對象

實例:

public class BufferedOutputStreamDemo01 {
	public static void main(String[] args) throws IOException {
		
		//寫數據到文件的方法
		write();
	}

	/*
	 * 寫數據到文件的方法
	 * 1,創建流
	 * 2,寫數據
	 * 3,關閉流
	 */
	private static void write() throws IOException {
		//創建基本的字節輸出流
		FileOutputStream fileOut = new FileOutputStream("abc.txt");
		//使用高效的流,把基本的流進行封裝,實現速度的提升
		BufferedOutputStream out = new BufferedOutputStream(fileOut);
		//2,寫數據
		out.write("hello".getBytes());
		//3,關閉流
		out.close();
	}
}

2. 字節緩衝輸入流 BufferedInputStream

構造方法

public BufferedInputStream(InputStream in);//創建一個 BufferedInputStream 並保存其參數,即輸入流 in,以便將來使用。

public BufferedInputStream(InputStream in,size);//創建具有指定緩衝區大小的 BufferedInputStream 並保存其參數,即輸入流 in,以便將來使用。

其參數爲字節輸入流的對象。

實例:

/*
	 * 從文件中讀取數據
	 * 1,創建緩衝流對象
	 * 2,讀數據,打印
	 * 3,關閉
	 */
	private static void read() throws IOException {
		//1,創建緩衝流對象
		FileInputStream fileIn = new FileInputStream("abc.txt");
		//把基本的流包裝成高效的流
		BufferedInputStream in = new BufferedInputStream(fileIn);
		//2,讀數據
		int ch = -1;
		while ( (ch = in.read()) != -1 ) {
			//打印
			System.out.print((char)ch);
		}
		//3,關閉
		in.close();
	}

使用基本的流與高效的流完成複製文件

我們一直在說,高效的流速度快並高效,怎麼體現呢?需要通過一個複製文件耗時的比較過程,來體驗一下高效流帶來的快感。

/*
 * 需求:將d:\\test.avi文件進行復制
 * 		採用4種方式複製
 * 		方式1: 採用基本的流,一次一個字節的方式複製	共耗時 224613毫秒
 * 		方式2: 採用基本的流,一個多個字節的方式賦值	共耗時     327毫秒
 * 		方式3: 採用高效的流,一次一個字節的方式複製	共耗時    2047毫秒
 * 		方式4: 採用高效的流,一個多個字節的方式賦值	共耗時      96毫秒
 * 
 * 數據源: d:\\test.avi
 * 目的地1: d:\\copy1.avi
 * 目的地2: d:\\copy2.avi
 * 目的地3: d:\\copy3.avi
 * 目的地4: d:\\copy4.avi
 * 
 * 實現的步驟:
 * 	1,指定數據源
 * 	2,指定目的地
 * 	3,讀數據
 * 	4,寫數據
 * 	5,關閉流
 * 
 */
public class CopyAVI {
	public static void main(String[] args) throws IOException {
		//開始計時
		long start = System.currentTimeMillis();
		//方式1: 採用基本的流,一次一個字節的方式複製
		//method1("d:\\test.avi", "d:\\copy1.avi");
		//方式2: 採用基本的流,一個多個字節的方式賦值
		//method2("d:\\test.avi", "d:\\copy2.avi");
		//方式3: 採用高效的流,一次一個字節的方式複製
		//method3("d:\\test.avi", "d:\\copy3.avi");
		//方式4: 採用高效的流,一個多個字節的方式賦值
		method4("d:\\test.avi", "d:\\copy4.avi");
		
		//結束計時
		long end = System.currentTimeMillis();
		//打印耗時多少毫秒
		System.out.println("共耗時 " +(end - start)+ "毫秒");
	}
	
	//方式4: 採用高效的流,一個多個字節的方式賦值
	private static void method4(String src, String dest) throws IOException {
		//1,指定數據源
		BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
		 //2,指定目的地
		BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
		 //3,讀數據
		byte[] buffer = new byte[1024];
		int len = -1;
		while ( (len = in.read(buffer)) != -1) {
			//4,寫數據
			out.write(buffer, 0, len);
		}
		 //5,關閉流
		in.close();
		out.close();
	}

	//方式3: 採用高效的流,一次一個字節的方式複製
	private static void method3(String src, String dest) throws IOException {
		//1,指定數據源
		BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
		 //2,指定目的地
		BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
		 //3,讀數據
		int ch = -1;
		while ((ch=in.read()) != -1) {
			//4,寫數據
			out.write(ch);	
		}		
		 //5,關閉流
		in.close();
		out.close();
	}

	//方式2: 採用基本的流,一個多個字節的方式賦值
	private static void method2(String src, String dest) throws IOException {
		//1,指定數據源
		FileInputStream in = new FileInputStream(src);
		//2,指定目的地
		FileOutputStream out = new FileOutputStream(dest);
		//3,讀數據
		byte[] buffer = new byte[1024];
		int len = -1;
		while ( (len=in.read(buffer)) != -1) {
			//4,寫數據
			out.write(buffer, 0, len);
		}
		//5,關閉流
		in.close();
		out.close();
	}

	//方式1: 採用基本的流,一次一個字節的方式複製
	private static void method1(String src, String dest) throws IOException {
		//1,指定數據源
		FileInputStream in = new FileInputStream(src);
		//2,指定目的地
		FileOutputStream out = new FileOutputStream(dest);
		//3,讀數據
		int ch = -1;
		while (( ch=in.read()) != -1) {
			//4,寫數據
			out.write(ch);
		}
		//5,關閉流
		in.close();
		out.close();
	}
}






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章