1. 程式人生 > >黑馬程式設計師——java的IO之字元流,位元組流,轉換流

黑馬程式設計師——java的IO之字元流,位元組流,轉換流

------- android培訓java培訓、期待與您交流! ----------

前言:通過觀看畢向東老師的java基礎視訊,查漏補缺,將一些自己掌握的還不牢固的知識寫出來,希望和大家交流分享。

1.IO概述

1、相關概念:IO:即Input和Output的縮寫。

2、作用和特點:

       1)IO流用來處理裝置間的資料傳輸。裝置包括記憶體和磁碟等.

       2)Java對資料的操作是通過流的方式。

       3)Java用於操作流的物件都在IO包中。

       4)流按操作資料分為兩種:位元組流和字元流。字元流是在位元組流的基礎之上,java的設計者為了方便對日常生活中的語言文字等操作而設計的.

       5)流按流向分為:輸入流和輸出流。

      注意:流只能操作資料,而不能操作檔案。

3、IO流的常用基類:

       1)位元組流的抽象基流:InputStream和OutputStream

       2)字元流的抽象基流:Reader和Writer

注:此四個類派生出來的子類名稱都是以父類名作為子類名的字尾,以字首為其功能;如InputStream子類FileInputStream;Reader子類FileReader

2.字元流

1、字串是我們日常生活中最熟悉的。字元流的操作更貼近生活,更易理解。

       1)字元流中的物件融合了編碼表。使用的是預設的編碼,即當前系統的編碼。

       2)字元流只用於處理文字資料,而位元組流可以處理媒體資料。

       3)既然IO流是用於操作資料的,那麼資料的最常見體現形式是檔案。檢視API,找到一個專門用於操作檔案的Writer子類物件:FileWriter。字尾是父類名,字首名是流物件的功能。該流物件一被初始化,就必須有被操作的檔案存在。

2、字元流的讀寫

      1)寫入字元流步驟

       a、建立一個FileWriter物件,該物件一被初始化,就必須要明確被操作的檔案。且該目錄下如果已有同名檔案,則同名檔案將被覆蓋。其實該步就是在明確資料要存放的目的地。

       b、呼叫write(String s)方法,將字串寫入到流中。

       c、呼叫flush()方法,重新整理該流的緩衝,將資料重新整理到目的地中。

       d、呼叫close()方法,關閉流資源。但是關閉前會重新整理一次內部的緩衝資料,並將資料重新整理到目的地中。

     2)close()和flush()區別:

       flush()重新整理後,流可以繼續使用;

       而close()重新整理後,將會關閉流,不可再寫入字元流。

       注意:其實java自身不能寫入資料,而是呼叫系統內部方式完成資料的書寫,使用系統資源後,一定要關閉資源。

3、程式碼例項:

  1)FileWriter的基本操作.

示例1,寫入檔案

package file;

import java.io.FileWriter;
import java.io.IOException;

public class FileWriterDemo {
	public static void main(String[] args) throws IOException {
		/*
		 * 建立一個FileWriter物件,該物件必須要明確被操作的檔案才能被初始化。
		 * 該檔案會被建立到指定目錄下,如果該目錄下已經有同名的檔案,將被覆蓋。
		 * 該步是 要明確資料要存放的位置。
		 */
		FileWriter fw = new FileWriter("demo.txt");
		
		//呼叫write方法將字串寫入到流中,即記憶體中的特定區域
		fw.write("abcde");
		
		//重新整理流物件中的緩衝中的資料,將資料刷到目的地中
		fw.flush();
		//繼續寫和重新整理
		fw.write("songwenju");
		fw.flush();
		
		fw.write("111");
		//關閉流資源,釋放所佔的記憶體空間,在執行close之前會把流中的資料重新整理到目的檔案中。
		//一個流一旦關閉就不能再寫了。
		fw.close();
	}
}

執行結果:


2)  檔案的資料的續寫是通過建構函式FileWriter(Strings,boolean append),在建立物件時,傳遞一個true引數,代表不覆蓋已有的檔案。並在已有檔案的末尾處進行資料續寫。(windows系統中的檔案內換行用\r\n兩個轉義字元表示,在linux系統中只用\n表示換行)

示例2:檔案續寫

package file;

import java.io.FileWriter;
import java.io.IOException;

/**
 * 對已有的檔案進行續寫
 * @author songwenju
 *
 */
public class FileWriterDemo2 {
	public static void main(String[] args) throws IOException {
		//傳遞一個true引數表示不覆蓋原有的檔案,而是在檔案的後面續寫
		FileWriter fw = new FileWriter("demo.txt",true);
		fw.write("O(∩_∩)O\r\n謝謝");
		fw.close();
	}
}

執行結果:


3)由於在建立物件時,需要指定建立檔案位置,如果指定的位置不存在,就會發生IOException異常,所以在整個步驟中,需要對IO異常進行try處理。

示例3:完整的IO異常處理

package file;

import java.io.FileWriter;

/**
 * 完整的IO異常處理
 * @author songwenju
 *
 */
public class IOException {
	public static void main(String[] args) {
		FileWriter fw = null;
		try {
			//初始化在裡面
			fw = new FileWriter("demo.txt");
			fw.write("111");
		} catch (java.io.IOException e) {
			e.printStackTrace();
		}finally{
			//判斷是否為空
			if (fw != null) {
				try {
					fw.close();
				} catch (java.io.IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

4)讀字元流

         讀取字元流步驟

        1)建立一個檔案讀取流物件,和指定名稱的檔案相關聯。要保證該檔案已經存在,若不存在,將會發生異常FileNotFoundException。

        2)呼叫讀取流物件的read()方法。read():一次讀一個字元,且會繼續往下讀。

             第一種方式:讀取單個字元。第二種方式:通過字元陣列進行讀取。

        3)讀取後要呼叫close方法將流資源關閉

 示例4:讀字元流
package file;

import java.io.FileReader;
import java.io.IOException;

/**
 * 讀字元流
 * @author songwenju
 *
 */
public class FileReaderDemo {
	public static void main(String[] args) throws IOException {
		FileReader fr = new FileReader("demo.txt");
		//呼叫讀取流物件的read方法
		//read一次只讀取一個字元,而且會主動往下讀,一直到-1
		
		/*System.out.println("ch1 = "+(char)fr.read());
		System.out.println("ch2 = "+(char)fr.read());
		System.out.println("ch3 = "+(char)fr.read());
		System.out.println("ch4 = "+(char)fr.read());
		System.out.println("ch5 = "+(char)fr.read());
		System.out.println("ch6 = "+fr.read());*/
		int ch;
		
		/*while (true) {
			ch = fr.read();
			if (ch == -1) {
				break;
			}
			System.out.println((char)ch);
		}*/
		while ((ch = fr.read()) != -1) {
			System.out.println((char)ch);
		}
		fr.close();
	}
}

5)檔案的複製

示例4:將D盤v5檔案中的file.java檔案拷貝到D盤v5的songwenju資料夾下。

package file;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 將D盤v5檔案中的file.java檔案拷貝到D盤v5的songwenju資料夾下
 * @author songwenju
 *	思路:先讀取,然後再寫入
 */
public class CopyFile {
	public static void main(String[] args) throws IOException {
		copy1();
		copy2();
		copy3();
	}
	public static void copy3(){
		FileReader fr = null;
		FileWriter fw = null;
		try {
			fr = new FileReader("D:/v5/File.java");
			fw = new FileWriter("D:/v5/songwenju/File3.java");
			char[] buf = new char[1024];
			int count;
			while((count = fr.read(buf)) != -1){
				fw.write(buf, 0, count);//這樣會讀多少寫多少,fw.write(buf)會寫入1024個字元。
			}
		} catch (IOException e) {
			throw new RuntimeException("流異常");
		}finally{
			try {
				if (fw != null) {
					fw.close();
				}
			} catch (IOException e2) {
				throw new RuntimeException("流異常");
			}
			
			try {
				if (fr != null) {
					fr.close();
				}
			} catch (Exception e2) {
				throw new RuntimeException("流異常");
			}
		}
	}
	/**
	 * 讀一個字元寫一個字元
	 * @throws IOException
	 */
	public static void copy2() throws IOException{
		FileReader fr = new FileReader("D:/v5/File.java");
		FileWriter fw = new FileWriter("D:/v5/songwenju/File2.java");
		int ch;
		while ((ch = fr.read()) != -1) {
			fw.write(ch);
		}
		fw.close();//必須要flush
		fr.close();
	}
	/**
	 * 自己寫的多了一步拼接
	 * @throws IOException
	 */
	public static void copy1() throws IOException{
		FileReader fr = new FileReader("D:/v5/File.java");
		FileWriter fw = new FileWriter("D:/v5/songwenju/File.java");
		char [] buf = new char[1024];
		int count;
		StringBuffer sBuffer = new StringBuffer();
		while((count = fr.read(buf)) != -1){//讀的時候要判斷是否讀到末尾,寫的時候一次寫完。
			//System.out.print(new String(buf,0,count));
			sBuffer.append(new String (buf,0,count));
		}
		fw.write(new String(sBuffer));
		fw.close();
		fr.close();
	}
}

4、字元流的緩衝區——BufferedReader和BufferedWriter

    1)緩衝區的出現:提高了流的讀寫效率,所以在緩衝區建立前,要先建立流物件。即先將流物件初始化到建構函式中。 

    2)緩衝技術原理:此物件中封裝了陣列,將資料存入,再一次性取出。

    3)寫入流緩衝區BufferedWriter的步驟:

             a)建立一個字元寫入流物件。

                 如:FileWriter fw=newFileWriter("buf.txt");

            b)為了提高字元寫入流效率。加入緩衝技術。只要將需要被提高效率的流物件作為引數傳遞給緩衝區的建構函式即可。

                 如: BufferedWriter bufw =new BufferedWriter(fw);

            c)呼叫write方法寫入資料到指定檔案

                 如:bufw.write("adfg");

           d)記住,只要用到緩衝區,就要記得重新整理。(關閉流同樣會重新整理,但為了排除意外事故,保證資料存在,建議寫入一次就重新整理一次)

                 如:bufw.flush();

           e)其實關閉緩衝區,就是在關閉緩衝區中的流物件。

                如: bufw.close();

           f )小知識:BufferedWriter緩衝區中提供了一個跨平臺的換行符:newLine();可以在不同作業系統上呼叫,用作資料換行。

              如:bufw.newLine();

      4)讀取流緩衝區BufferedReader

            該緩衝區提供了一個一次讀一行的方法readLine,方便於堆文字資料的獲取,當返回null時表示讀到檔案末尾。

           readLine方法返回的時候,只返回回車符之前的資料內容。並不返回回車符。

      5)readLine方法原理:

          無論是讀一行。或者讀取多個字元。其實最終都是在在硬碟上一個一個讀取。所以最終使用的還是read方法一次讀一個的方法。

      6)使用緩衝區讀出資料BufferReader的步驟:

             a)建立一個讀取流物件和檔案相關聯

                  如: FileReader fr=newFileReader("buf.txt");

            b)為了提高效率。加入緩衝技術。將字元讀取流物件作為引數傳遞給緩衝區物件的建構函式。

                 如: BufferedReader bufr=new BufferedReader(fr);

            c)呼叫該緩衝區提供的readLine方法一行一行讀取,如果到達檔案末尾,則返回null

                 如: String s=bufr.readLine();

            d)關閉流資源

                 如: bufr.close();

示例:通過緩衝區複製一個文字檔案。

package file;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 通過緩衝區copy一個.java檔案
 * @author songwenju
 *
 */
public class CopyFileByBuffer {
	public static void main(String[] args) {
		BufferedReader bufr = null;
		BufferedWriter bufw = null;
		try {
			//這裡就是巢狀流了。
			bufr = new BufferedReader(new FileReader("D:/v5/File.java"));
			bufw = new BufferedWriter(new FileWriter("D:/v5/FileBuffer.java"));
			String line = null;
			while ((line = bufr.readLine())!=null) {
				bufw.write(line);
				//readLine包含該行內容的字串,不包含任何行終止符,如果已到達流末尾,則返回 null ,故加上newLine
				bufw.newLine();
				bufw.flush();
			}
		} catch (IOException e) {
			throw new RuntimeException("檔案讀寫錯誤");
		}finally{
			try {
				if (bufw != null) {
					bufw.close();
				}
			} catch (IOException e2) {
				throw new RuntimeException("檔案寫關閉錯誤");
			}
			try {
				if (bufr != null) {
					bufr.close();
				}
			} catch (IOException e2) {
				throw new RuntimeException("檔案讀關閉錯誤");
			}
		}
	}
}
5.模擬BufferReader

原理:根據BufferedReader類中特有一行一行讀取方法readLine()的原理,自定義一個類中包含相同功能的方法

步驟:

        a、初始化自定義的類,加入流物件。

        b、定義一個臨時容器,原BufferedReader封裝的是字元陣列,此類中可定義一個StringBuilder的容器,最終可實現字串的提取。

package file;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

class MyBufferReader extends Reader{//對每個Reader的子類都能增強
	private Reader r;//定義接收流的物件
	public MyBufferReader(Reader r) {
		this.r = r;
	}
	//自定義整行讀取  
	public String myReadLine()throws IOException{
		//建立一個容器,用來儲存一行的字元  
		StringBuilder sb = new StringBuilder();
		for (int ch = 0; (ch = r.read())!= -1;) {
			//如果遇到換行符,則跳過後面的內容
			if (ch == '\r') {
				continue;
			}
			//如果遇到回車符,表示該行讀取完畢 
			if (ch == '\n') {
				return sb.toString();
			}else {
				sb.append((char)ch);//將該行的字元新增到容器  
			}
		}
		//如果讀取結束,容器中還有字元,則返回元素
		if (sb.length() != 0) {
			return sb.toString();
		}
		return null;
	}
	@Override
	public int read(char[] cbuf, int off, int len) throws IOException {
		return r.read(cbuf, off, len);
	}

	@Override
	public void close() throws IOException {
		r.close();
	}
}
public class MyBufferReaderDemo{
	public static void main(String[] args) {
		MyBufferReader mReader = null;
		try {
			mReader = new MyBufferReader(new FileReader("demo.txt"));
			for (String line = null; (line = mReader.myReadLine())!= null;){
				System.out.println(line);
			}
		} catch (FileNotFoundException e) {
			throw new RuntimeException("檔案找不到");
		} catch (IOException e) {
			throw new RuntimeException("IO異常");
		}finally{
			try {
				if (mReader != null) {
					mReader.close();
				}
			} catch (IOException e2) {
				throw new RuntimeException("流關閉異常");
			}
		}
	}
}

執行結果:(示自己的檔案內容而定)

6.裝飾設計模式

1)當想對已有物件進行功能增強時,可定義類:將已有物件傳入,基於已有物件的功能,並提供加強功能,那麼自定義的該類稱之為裝飾類。

2) 裝飾類通常都會通過構造方法接收被裝飾的物件,如果直接改原始碼會造成災難性的後果,並基於被裝飾的物件的功能,提供更強的功能。

3)裝飾和繼承的區別:

        1)裝飾模式比繼承要靈活。避免了繼承體系的臃腫(有時候為了添加個別共同的功能每個類都要新增該功能的子類就造成了臃腫,

           不如抽取改方法用去裝飾),且降低了類與類之間的關係。

        2)裝飾類因為增強已有物件,具備的功能和已有的是相同的,只不過提供了更強的功能,所以裝飾類和被裝飾的類通常都是屬於一個體系。

        3)從繼承結構轉為組合結構。

注:在定義類的時候,不要以繼承為主;可通過裝飾設計模式進行增強類功能。靈活性較強,當裝飾類中的功能不適合,可再使用被裝飾類的功能。

程式碼示例:
package file;

/**
 * 裝飾設計模式
 * @author songwenju
 *
 */
class Person{
	public void eat(){
		System.out.println("吃飯");
	}
}
class DecoratePerson{
	private Person p;
	public DecoratePerson(Person p) {
		this.p = p;
	}
	public void decorateEat(){
		System.out.println("開胃菜");
		p.eat();
		System.out.println("甜點");
	}
}
public class DecorateDemo {
	public static void main(String[] args) {
		Person person = new Person();
		DecoratePerson dPerson = new DecoratePerson(person);
		dPerson.decorateEat();
	}
}
7.LineNumberReader

   在BufferedReader中有個直接的子類LineNumberReader,其中有特有的方法獲取和設定行號:

         setLineNumber();//設定初始行號

         getLineNumber();//獲取行號

程式碼示例:
package file;

import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;

/**
 * LineNumberReader練習
 * @author songwenju
 *
 */
public class LineNumberReaderDemo {
	public static void main(String[] args) throws IOException {
		//使用相對路徑要加src
		FileReader fReader = new FileReader("src/file/FileListDemo.java");
		
		LineNumberReader lReader = new LineNumberReader(fReader);
		String line = null;
		//lReader.setLineNumber(100);
		while((line = lReader.readLine())!= null){
			System.out.println(lReader.getLineNumber()+"   "+line);
		}
		lReader.close();
	}
}
執行結果:

4.位元組流

1.位元組流和字元流的基本操作是相同的,但位元組流還可以操作其他媒體檔案。

2.由於媒體檔案資料中都是以位元組儲存的,所以,位元組流物件可直接對媒體檔案的資料寫入到檔案中,而可以不用再進行刷流動作。

因為位元組流操作的是位元組,即資料的最小單位,不需要像字元流一樣要進行轉換為位元組。所以可直接將位元組資料寫入到指定檔案中。

3.InputStream   輸入流(讀)  OutputStream  輸出流(寫)

4.位元組流基本操作程式碼示例:

package file;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 位元組流的操作
 * @author songwenju
 *
 */
public class FileStream {
	public static void main(String[] args) throws IOException {
		//writeFile();
		//readFile_1();
		//readFile_2();
		readFile_3();
	}
	/**
	 * 以1024位元組大小為塊進行讀取
	 * @throws IOException
	 */
	public static void readFile_3() throws IOException {
		InputStream  in = new FileInputStream("fos.txt");
		int num = in.available();//得到檔案的大小,該方法慎用。如果檔案比較大大於虛擬機器的記憶體,會報錯。
		//故第2種方法比較好。
		
		System.out.println(num);//3
		byte[] b = new byte[in.available()];
		in.read(b);
		System.out.println(new String (b,0,b.length));
		in.close();
	}
	/**
	 * 以1024位元組大小為塊進行讀取
	 * @throws IOException
	 */
	public static void readFile_2() throws IOException {
		InputStream  in = new FileInputStream("fos.txt");
		byte [] b = new byte[1024];//1024的整數倍
		int len = 0;
		while ((len = in.read(b))!= -1) {
			System.out.println(new String(b,0,len));
		}
		in.close();
	}
	
	/**
	 * 一個一個位元組的讀,讀出的資料是int型別轉化為char
	 * @throws IOException
	 */
	public static void readFile_1() throws IOException {
		InputStream in = new FileInputStream("fos.txt");
		
		int b = 0;
		while ((b =  in.read())!= -1) {
			System.out.println((char)b);
			
		}
		in.close();
	}
	
	/**
	 * 寫入內容
	 * @throws IOException
	 */
	public static void writeFile() throws IOException {
		OutputStream out = new FileOutputStream("fos.txt");
		//字串轉換為位元組陣列:"abcde".getBytes()
		//字串轉換為字元陣列:"abcde".toCharArray()
		out.write("abc".getBytes());
		//字元流底層也是使用的是位元組流.
		//位元組流不需要緩衝,也就是不需要重新整理,他是對資料最小單位操作。但還要關閉資源。
		out.close();
	}
}
5.複製一個圖片程式碼示例:
package file;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 複製圖片用位元組流
 * 如果用字元流複製會出現亂碼情況,而位元組流不會,它複製的是01
 * @author songwenju
 *
 */
public class CopyPicture {
	public static void main(String[] args) throws IOException {
		copyFile();
	}
	
	/**
	 * 推薦使用的方法
	 * @throws IOException
	 */
	public static void copyFile() throws IOException{
		InputStream in = new FileInputStream("src/file/1.png");
		OutputStream out = new FileOutputStream("src/file/2.png");
		byte[] b = new byte[1024];
		int len = 0;
		while((len = in.read(b)) != -1){
			out.write(b, 0, len);
		}
		out.close();
		in.close();
		
	}
}
6.位元組流緩衝區

        同樣是提高了位元組流的讀寫效率。

    1)讀寫特點:

        read():會將位元組byte型值提升為int型值

        write():會將int型強轉為byte型,即保留二進位制數的最後八位。

   2)原理:將資料拷貝一部分,讀取一部分,迴圈,直到資料全部讀取完畢。

        a)先從資料中抓取固定陣列長度的位元組,存入定義的陣列中,再通過然後再通過read()方法讀取陣列中的元素,存入緩衝區。

        b)迴圈這個動作,直到最後取出一組資料存入陣列,可能陣列並未填滿,同樣也取出包含的元素。

        c)每次取出的時候,都有一個指標在移動,取到陣列結尾就自動回到陣列頭部,這樣指標在自增。

        d)取出的時候,陣列中的元素在減少,取出一個,就減少一個,直到減到0即元素取完。

        e)當檔案中的全部資料都被讀取出時,read()方法就返回-1。

   3)自定義讀取位元組流緩衝區

        需求:根據位元組流緩衝區的原理,自定義一個位元組流緩衝區。

       注意:

        1、位元組流的讀一個位元組的read方法為什麼返回值型別不是byte,而是int。

       因為有可能會讀到連續8個二進位制1的情況,8個二進位制1對應的十進位制是-1.那麼就會資料還沒有讀完,就結束的情況。因為我們判斷讀取結束是通過結尾標記-1來確定的。

       所以,為了避免這種情況將讀到的位元組進行int型別的提升。並在保留原位元組資料的情況前面了補了24個0,變成了int型別的數值。而在寫入資料時,只寫該int型別資料的最低8位。

        2、byte型別的-1提升為int型別時還是-1。原因:因為在bit8個1前面補的全是1導致的。如果在bit8個1前面補0,即可以保留原位元組資料不變,又可以避免-1的出現。這時將byte型資料&0xff即255即可。

程式碼示例:自定義BufferInputStream

package file;

import java.io.IOException;
import java.io.InputStream;

/**
 * 自定義bufferInputStream
 * @author songwenju
 *
 */
public class MyBufferInputStream {
	private InputStream in;
	private byte[] b = new byte[1024];
	private int count = 0,pos = 0;
	public MyBufferInputStream(InputStream in) {
		this.in = in;
	}
	
	//自定義讀方法,一次讀一個位元組  
	public int myRead() throws IOException{
		//通過in物件讀取硬碟上資料,並存儲b中。  
        //儲存在陣列中的資料被讀取完,再通過in物件從硬碟上讀取資料  
		if (count == 0) {
			count = in.read(b);
			if (count < 0) {//檔案資料全部被讀取出來了  
				return -1;
			}
			pos = 0;//初始化指標  
			byte by = b[pos];
			count--;//每被讀一個位元組,表示陣列中的位元組數少一個  
			pos++;//指標加1  
			//返回的byte型別提升為int型別,位元組數增加,且高24位被補1,原位元組資料改變。  
			//通過與上255,主動將byte型別提升為int型別,將高24位補0,原位元組資料不變。  
            //而在輸出位元組流寫入資料時,只寫該int型別資料的最低8位。 
			return by&0xff;
		}else if (count > 0) {//如果陣列中的資料沒被讀取完,則繼續讀取 
			byte by = b[pos];
			count--;
			pos++;
			return by&0xff;
		}
		return -1;
	}
	 //自定義關閉資源方法  
	public void close()throws IOException{
		in.close();
	}
}

該類的使用:

package file;

import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyMP3 {
	public static void main(String[] args) throws IOException {
		long start = System.currentTimeMillis();
		copyFile();
		long end = System.currentTimeMillis();
		System.out.println("一共用了"+(end - start)+"毫秒");
		
	}
	public static void copyFile() throws IOException{
		MyBufferInputStream bin = new MyBufferInputStream(new FileInputStream("src/file/0.mp3"));
		BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream("src/file/2.mp3"));
		
		int b = 0;
		while((b = bin.myRead())!= -1){
			bout.write(b);
		}
		bout.close();
		bin.close();
	}
}
執行結果:

5.轉換流

1.鍵盤錄入

        1)標準輸入輸出流

              System.in:對應的標準輸入裝置,鍵盤。

              Sytem.out:對應的是標準的輸出裝置,控制檯。

              System.in的型別是InputStream.  API中:public static final InputStream in

              System.out的型別是PrintStream是OutputStream的子類FilterOutputStream的子類。

程式碼示例:

package file;

import java.io.IOException;
import java.io.InputStream;

/**
 * 讀取鍵盤錄入
 * @author songwenju
 *
 */
public class ReadIn {
	public static void main(String[] args) throws IOException {
		InputStream in = System.in;
		
		// \r的ASCII碼是: 13
		System.out.println("\\r的ASCII碼是: "+('\r'+0));
		//\n的ASCII碼是: 10
		System.out.println("\\n的ASCII碼是: "+('\n'+0));
		
		int b = in.read();
		int b1 = in.read();
		int b2 = in.read();
		System.out.println(b);//輸入abc,輸出97,只讀一個位元組
		System.out.println(b1);//輸入abc,輸出97,98,讀兩個位元組	
		System.out.println(b2);//輸入a,輸出97,13,10,讀兩個位元組,可知在Windows中換行是\r\n	
	}
}

2.整行錄入

當使用輸入流進行鍵盤錄入時,只能一個位元組一個位元組進行錄入。為了提高效率,可以自定義一個數組將一行位元組進行儲存。

自定義讀入一行:

package file;

import java.io.IOException;
import java.io.InputStream;

/**
 * 自己寫的讀取一行資料
 * @author songwenju
 *
 */
public class ReadLine {
	public static void main(String[] args) throws IOException {
		InputStream in = System.in;
		StringBuilder sb = new StringBuilder();
		//就是上面寫的readLine方法
		while (true) {
			int ch = in.read();
			if (ch == '\r') {
				continue;
			}
			if (ch == '\n') {
				String s = sb.toString();
				if ("over".equals(s)) {
					break;
				}
				System.out.println(s.toUpperCase());
				sb.delete(0, sb.length());//清空內容
			}else {
				sb.append((char)ch);
			}
		}
	}
}

當一行錄入完畢,再將一行資料進行顯示。這種正行錄入的方式,和字元流讀一行資料的原理是一樣的。也就是readLine方法。

那麼能不能直接使用readLine方法來完成鍵盤錄入的一行資料的讀取呢?

     readLine方法是字元流BufferedReader類中方法。而鍵盤錄入的read方法是位元組流InputStream的方法。

那麼能不能將位元組流轉成字元流再使用字元流緩衝區的readLine方法呢?

      這就需要用到轉換流了。

3.轉換流

     1) 轉換流的由來:字元流與位元組流之間的橋樑。方便了字元流與位元組流之間的操作。轉換流的應用:位元組流中的資料都是字元時,轉成字元流操作更高效。

     2)InputStreamReader將位元組流通向字元流的步驟:

             a)獲取鍵盤錄入物件。

                  InputStream in=System.in;

             b)將位元組流物件轉成字元流物件,使用轉換流。

                 InputStreamReader isr=new InputStreamReader(in);

             c)為了提高效率,將字串進行緩衝區技術高效操作。使用BufferedReader

                 BufferedReaderbr=new BufferedReader(isr);

                //鍵盤錄入最常見寫法

                 BufferedReader  in=new BufferedReader(new InputStreamReader(System.in));

     3)OutputStreamWriter字元流通向位元組流

           字元通向位元組:錄入的是字元,存到硬碟上的是位元組。步驟和InputStreamReader轉換流一樣。

          程式碼示例:

package file;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

/**
 * 將鍵盤錄入的資料,顯示在檔案,當輸入over時,表示結束 
 * @author songwenju
 *
 */
public class TransferStream {
	public static void main(String[] args) throws IOException {
		/*//獲取鍵盤錄入物件。  
		InputStream in = System.in;
		//將位元組流物件轉成字元流物件,使用轉換流。
		InputStreamReader isr = new InputStreamReader(in);
		//為了提高效率,將字串進行緩衝區技術高效操作。使用BufferedReader  
		BufferedReader bufr = new BufferedReader(isr);*/
		
		//以上三句話變一句話
		BufferedReader bufr = new BufferedReader(
				new InputStreamReader(System.in));
		
		
		//將字元流轉換為位元組流OutputStreamWriter
		
		/*OutputStream out = System.out;
		OutputStreamWriter osw = new OutputStreamWriter(out);
		BufferedWriter bufw = new BufferedWriter(osw);
		*/
		//以上三句變一句,這一句是鍵盤錄入的最常見寫法
		BufferedWriter bufw = new BufferedWriter(
				new OutputStreamWriter(new FileOutputStream("os.txt")));
		
		String line = null;
		while ((line = bufr.readLine())!= null) {
			if ("over".equals(line)) {
				break;
			}
			//有了輸出後就不用這個了,直接用osw
			//System.out.println(line.toUpperCase());
			bufw.write(line.toUpperCase());
			bufw.newLine();
			bufw.flush();
		}
		bufw.close();
		bufr.close();
	}
}
執行結果:


------- android培訓java培訓、期待與您交流! ----------

相關推薦

黑馬程式設計師——JavaString類、基本資料型別物件包裝類等

    例如:parseInt("0", 10) 返回 0。        parseInt("473", 10) 返回 473。        parseInt("-0", 10) 返回 0。        parseInt("-FF", 16) 返回 -255。        parseInt("1100

黑馬程式設計師java集合框架Collection

 ------- <a href="http://www.itheima.com" target="blank">android培訓</a>、<a href="http://www.itheima.com" target="blank"&g

黑馬程式設計師—馬上快畢業了給你們點建議吧

首先就是基礎重要不重要,這個不好做定論,因為看你需要掌握的程度,黑馬這邊的課程需要基礎在視訊裡都有,老畢的25天和張老師的高新技術,這些全部會用到,把這些全看熟了,並掌握原理才是關鍵,你去看什麼字串有操作建立幾個物件這種的,自己提高可以,但對聽課無幫助,除非你已經進入記憶體管理或者告訴快取等方面的應用才會逐漸

黑馬程式設計師—寫給各位同學並致黑馬各位老師的一封感謝信~~~~絕對給力

      我來自黑馬五期的一個普通學員,這封感謝信,我不想寫的那麼多,因為再多的話語也寫不盡我心裡對黑馬這個機構的感激,對黑馬所有老師的感激。方立勳老師是黑馬的CEO,和他相處過的同學都知道他是一個平易近人,學識淵博的老師,從來不會擺架子,和他溝通很有親切感,我認為這樣的老師,這樣的領導是最偉大的。同樣我要

黑馬程式設計師--java高新技術 25--列舉反射

---------------------- ASP.Net+Android+IO開發S、.Net培訓、期待與您交流! ---------------------- /*1.5 新特性總結: 靜態匯入 可變引數 增強for(foreach) 基本資料的自動拆裝箱 列舉 泛

黑馬程式設計師------java中的反射beanutils註解的應用。

Class類:描述眾多java類的物件。代表記憶體裡的一份位元組碼。 有三種方式可以獲取一個類的Class檔案。 方法一:是通過該類物件.getClass()方法。 方法二:通過Class類的靜態方法,Class.forName("name"); 方法三:

黑馬程式設計師——JAVA大話資料結構

         對於資料結構來說,不論是c還是java,都是重中之重,為什麼是資料結構呢?我個人覺得是對資料的分析,解釋能力,引文軟體是什麼,是計算機資料和一系列的集合,當然,資料很重要了,現在的大資料來說,大資料時代的到來,影響著人們的方方面面,然後手機還是對人們影響更

黑馬程式設計師--java基礎--String,StringBufferStringBuilde

------- android培訓、java培訓、期待與您交流! --------- String的兩種例項化方式: 方式1: String s1 = "abc"; //s1是一個類型別變數,"abc"是一個物件 //字串最大的特點:String一旦初始化

黑馬程式設計師——ocself的使用

、期待與您交流! ---------- 首先我們建立一個學生類:Student類 這個學生類裡有學生的id和學生的姓名name #import @interface  Student : NSObject{  //idname NSString *id;  NSSt

黑馬程式設計師————面向物件(概述封裝建構函式thisstatic)

概述:     面向物件(Object Oriented,OO)是當前計算機界關心的重點,它是90年代軟體開發方法的主流。面向物件的概念和應用已超越了程式設計和軟體開發,擴充套件到很寬的範圍。如資料庫系統、互動式介面、應用結構、應用平臺、分散式系統、網路管理結構、CAD技術

黑馬程式設計師--高新技術動態代理

                                ------- android培訓、java培訓、期待與您交流! ---------- 一、關於動態代理的一些基本概念     在程式設計中,很多時候我們要為已存在的多個具有相同介面的目標類的各個     方法

黑馬程式設計師---面向物件上(封裝繼承多型)

------<a href="http://www.itheima.com" target="blank">Java培訓、Android培訓、iOS培訓、.Net培訓</a>、期待與您交流! 面向物件(Object-Oriented,簡稱OO)

黑馬程式設計師_BeanUtils包的使用主要是BeanUtils和PropertyUtils的區別

  ----------------------    android培訓java培訓   期待與您交流!    ----------------------  用BeanUtils工具包時,先要把兩個Jar包進行Building Path,就是引入兩個jar包,

黑馬程式設計師_OC記憶體管理

記憶體管理 ------ IOS培訓、android培訓、期待與您交流!------- 一、基本原理:    1、記憶體管理的定義       1>、移動移動裝置的記憶體極其有限,每個app所能佔用的記憶體是有限制的       2>、當app所佔用的記憶體

黑馬程式設計師——JavaSE網路程式設計總結一

網路模型   OSI(Open System Interconnection開放系統互連)參考模型   TCP/IP參考模型 網路通訊要素   IP地址   埠號   傳輸協議 OSI七層

黑馬程式設計師--java基礎--多型內部類異常等

------- android培訓、java培訓、期待與您交流! --------- 多型: 允許不同類的物件對同一訊息作出響應 1.多型的體現 父類的引用指向自己的子類物件 父類的引用也可以接受自己的子類物件 2.多型的前提 類和類之間有關係。繼承。實現。 存在覆蓋。

黑馬程式設計師-File類檔案操作知識梳理與簡單應用

-------------------------------------Android培訓                      java培訓  期待與您的交流!------------------------------------------/*     檔案類的

程式設計師必備終端模擬器讓你的終端世界多一抹“顏色”

![](https://img2020.cnblogs.com/blog/759200/202003/759200-20200331082406527-1125855478.jpg) 作者:[HelloGitHub-ChungZH](https://chungzh.cn/) 當你逐漸厭倦了 cmd 的枯

黑馬程式設計師——java的IO字元位元組,轉換

------- android培訓、java培訓、期待與您交流! ---------- 前言:通過觀看畢向東老師的java基礎視訊,查漏補缺,將一些自己掌握的還不牢固的知識寫出來,希望和大家交流分享。 1.IO概述 1、相關概念:IO:即Input和Output的縮寫。

黑馬程式設計師——Java IO(一)IO概述、字元位元組

-----------android培訓、java培訓、java學習型技術部落格、期待與您交流!------------ IO流 一、概述 1.IO流是用來處理裝置之間的資料傳輸。  2.Java對資料的操作時通過流的方式。  3.Java用於操作流的物件都在IO包中。