Java基礎_IO流(上)

IO流(上)

一、概述:

    IO流:即Input、Output流,輸入、輸出流。在java中,對數據的操作通過流的形式完成;流可以按照操作對象的不同分爲字符流(專門用於操作純文本文件)和字節流(非純文本文件)兩種,也可以按照流向的不同分爲輸入流和輸出流,這裏的輸入和輸出都是相對於內存而言的。

    總之:IO流專門用來處理設備之間的數據傳輸;字符流=字節流+默認的編碼。

本章要介紹的字符流類如下圖所示:

本章要介紹的字節流類如下圖所示:


二、字符流

    字符流有默認的編碼,一般用於操作純文本的數據

    字符流的兩個抽象基類:Reader(讀取數據),Writer(寫出數據,內存寫到外設中);這兩個抽象基類提供了對於字符流操作的基本方法,但有些方法是抽象的,必須由子類去覆蓋。一切操作字符流的類都直接或者間接繼承Reader、Writer抽象基類;這些子類的後綴是父類名稱,前綴是具體的功能,例如:FileReader、BufferedReader、FileWriter、BufferedWriter等等。

    既然IO流用於操作數據,那麼數據的最常見體現形式就是:文件。在IO流中,有專門的類作文件數據的流對象,這兩個類就是FileReader、FileWriter

    flush()方法:調用write方法,只是把數據寫入到流中;而flush方法用於將流中的數據刷到目的文件中;注意:讀取流沒有刷新這種說法。

    爲了能更加清晰、更加深刻的理解,下面主要以代碼的形式介紹:

往磁盤文件中寫入數據:

package itheima.day18;

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

//需求:在硬盤上,創建一個文件並寫入一些文字數據
public class FileWriterDemo {

	public static void main(String[] args)  {
		FileWriter fw = null;
		try {
//			append爲true時,不覆蓋原文件
			fw = new FileWriter("D:\\java\\IODemoFile\\demo.txt"/*,true*/);
			fw.write("堅韌的民族主義者---蔣中正;");
			fw.flush();
			fw.write("抗日英雄----李宗仁;");
			fw.write("當代小諸葛---白崇禧;");
			fw.flush();
		} catch (IOException e) {
			throw new RuntimeException("文件讀寫失敗");
		}finally{
			try {
				if(fw!=null)
					fw.close();
			} catch (IOException e) {
				throw new RuntimeException("文件關閉失敗");
			}
		}
	}

}

1、讀取一個.java文件,並打印到控制檯上:

package itheima.day18;

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

public class FileReaderTest {
	public static void main(String[] args) {
		FileReader fr = null;
		try {
			fr = new FileReader("D:\\java\\workspace1\\JavaFoundation\\src\\itheima\\day18\\FileReaderTest.java");
			char[] buf = new char[1024];
			int num=0;
			while((num=fr.read(buf))!=-1){
				System.out.print(new String(buf,0,num));
			}
		} catch (FileNotFoundException e) {
			throw new RuntimeException("文件未找到異常!");
		} catch (IOException e) {
			throw new RuntimeException("IO讀寫異常!");
		}finally{
			try {
				if(fr!=null)
					fr.close();
			} catch (IOException e) {
				throw new RuntimeException("文件關閉失敗!");
			}
		}
	}
}

2、複製一個文件:

package itheima.day18;

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

//需求:將c盤一個文件複製到D盤(主要是演示文件的複製)
//	複製原理:其實就是將C盤下的文件數據存儲到D盤的一個文件中。
//	 步驟:
// 		1、在D盤創建一個文件,用於存儲c盤文件中的數據
// 		2、定義讀取流和C盤文件關聯
//  	3、通過不斷的讀寫完成數據的存儲
public class CopyTest {

	public static void main(String[] args) {
		copy_2();	
	}
	public static void copy_1(){
		
		FileWriter fw =null;
		FileReader fr = null;
		try {
			fw = new FileWriter("D:\\java\\IODemoFile\\CopyTest.java");
			fr = new FileReader("D:\\java\\workspace1\\JavaFoundation\\src\\itheima\\day18\\CopyTest.java");
			int ch =0;
			while((ch =fr.read())!=-1){
				fw.write((char)ch);
				fw.flush();
			}
		} catch (FileNotFoundException e) {
			throw new RuntimeException("文件未找到異常!");
		} catch (IOException e) {
			throw new RuntimeException("IO讀取異常!");
		}finally{
			try {
				if(fw!=null)
					fw.close();
			} catch (IOException e) {
				throw new RuntimeException("寫入文件關閉失敗!");
			}
			try {
				if(fr!=null)
					fr.close();
			} catch (IOException e) {
				throw new RuntimeException("讀取文件關閉異常!");
			}
		}
	}
	public static void copy_2(){
		FileWriter fw =null;
		FileReader fr = null;
		try {
			fw = new FileWriter("D:\\java\\IODemoFile\\CopyTest.java");
			fr = new FileReader("D:\\java\\workspace1\\JavaFoundation\\src\\itheima\\day18\\CopyTest.java");
			char[] buf = new char[1024];
			int  len =0;
			while((len =fr.read(buf))!=-1){
				fw.write(buf,0,len);
				fw.flush();
			}
		} catch (FileNotFoundException e) {
			throw new RuntimeException("文件未找到異常!");
		} catch (IOException e) {
			throw new RuntimeException("IO讀寫異常!");	
		}finally{
			try {
				if(fw!=null)
					fw.close();
			} catch (IOException e) {
				throw new RuntimeException("寫入文件關閉失敗!");
			}
			try {
				if(fr!=null)
					fr.close();
			} catch (IOException e) {
				throw new RuntimeException("讀取文件關閉失敗!");
			}
		}
	}
}

    字符流的緩衝區:緩衝區的出現是爲了提高對數據的讀寫效率;對應類:BufferedReader、BufferedWriter,注意:緩衝區只是在流的基礎上對流的功能進行增強,所以必須首先有流對象。

    BufferedWriter:將文本寫入字符輸出流,緩衝各個字符,從而提供單個字符、數組和字符串的高效寫入,最重要的增加了newLine()方法。

    BufferedReader:從字符輸入流中讀取文本,緩衝各個字符,從而實現字符、數組和行的高效讀取,最重要的是增加了readLine()方法。

    void  newLine(): 寫入一個行分隔符。

    String  readLine():讀取一個文本行,只返回數據,不返回回車符。

    readLine()方法的原理:無論是讀一行、獲取多個字符,還是讀取一個字符,其實最終都是在硬盤上一個一個的讀取。所以readLine()方法最終使用的還是read()一次讀一個的方法。

3、通過緩衝區複製一個.java文件:

package itheima.day19;

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

//通過緩衝區複製一個.java文件
public class CopyTextByBuffered {

	public static void main(String[] args) {
		
		BufferedReader bufr = null;
		BufferedWriter bufw = null;
		try {
			bufr =new BufferedReader(
					new FileReader(
							"D:\\java\\workspace1\\JavaFoundation\\src\\itheima\\day19\\CopyTextByBuffered.java"));
			bufw = new BufferedWriter(
					new FileWriter("D:\\java\\IODemoFile\\CopyTestByBuf.java"));
			String line =null;
			while((line = bufr.readLine())!=null){
				System.out.println(line);
				bufw.write(line);
				bufw.newLine();
				bufw.flush();
			}
		} catch (IOException e) {
			throw new RuntimeException("文件讀取失敗!");
		}finally{
			try {
				if(bufr!=null)
					bufr.close();
			}catch (IOException e) {
				throw new RuntimeException("文件讀取關閉失敗!");
			}
			try {
				if(bufw!=null)
					bufw.close();
			}catch (IOException e) {
				throw new RuntimeException("文件寫出關閉失敗!");
			}
		}
		System.out.println("複製完成!!!");
	}
}

    裝飾設計模式:當想要對已有的對象進行功能增強時,可以定義一個類,將已有對象傳入,基於已有的功能,並提供加強功能;那麼自定義的該類成爲裝飾類。裝飾類通常會通過構造方法接收被裝飾的對象,並基於被裝飾對象的功能,提供更強的功能。

    裝飾設計模式比繼承更加靈活,不僅避免了繼承體系的臃腫,還降低了類與類之間的耦合關係。裝飾類因爲只是增強已有對象,具備的功能和已有對象的功能是相同的,只不過提供了更強的功能,所以裝飾類和被裝飾類通常都屬於同一個體系中。

4、模擬帶有ReadLine功能的BufferedReader:

package itheima.day19;

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

// 定義MyBufferedReader,myReadLine方法
public class MyBufferedReaderDemo 
{
	public static void main(String[] args) {
		
		MyBufferedReader myBuf = null;
		try {
			FileReader fr = new FileReader("D:\\java\\IODemoFile\\CopyTestByBuf.java");
			myBuf = new MyBufferedReader(fr);
			String line = null;
			while((line = myBuf.myReadLine())!=null){
				System.out.println(line);
			}
		} catch (FileNotFoundException e) {
			throw new RuntimeException("要讀取的文件不存在!");
		} catch (IOException e) {
			throw new RuntimeException("文件讀寫失敗!");
		}finally{
			try {
				if(myBuf!=null)
					myBuf.myClose();
			} catch (IOException e) {
				System.out.println(e.toString());
			}
		}
	}
}
class MyBufferedReader extends Reader
{
	private Reader r;
	MyBufferedReader(Reader r){
		this.r  = r;
	}
	public String myReadLine() throws IOException{
		.
		StringBuilder sb = new StringBuilder();
		int ch =0;
		while((ch =r.read())!= -1){
			if(ch =='\r')
				continue;
			if(ch =='\n')
				return sb.toString();
			sb.append((char)ch);
		}
		if(sb.length()!=0)
			return sb.toString();
		return null;
	}
	public void myClose() throws IOException{
		r.close();
	}
	@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();
	}	
}

5、模擬帶有行號功能的LineNumberReader:

package itheima.day19;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import itheima.day19.MyBufferedReader;

public class MyLineNumberReaderDemo {

	public static void main(String[] args) {
		
		 MyLineNumberReader mylnr = null;
		try {
			FileReader fr = new FileReader("src\\itheima\\day19\\LineNumberReaderDemo.java");
			 mylnr = new MyLineNumberReader(fr);
			 String line = null;
			 mylnr.setLineNumber(200);
			 while((line = mylnr.myReadLine())!=null){
				 System.out.println(mylnr.getLineNumber()+"::"+line);
			 }
		} catch (FileNotFoundException e) {
			throw new RuntimeException("文件未找到異常!");
		} catch (IOException e) {
			throw new RuntimeException("文件讀寫異常!");
		}finally{
			try {
				if(mylnr!=null)
					mylnr.myClose();
			} catch (IOException e) {
				throw new RuntimeException("文件關閉失敗!");
			}
		}
	}
}

class MyLineNumberReader extends MyBufferedReader
{
	private int lineNumber;
	MyLineNumberReader(Reader r){
		super(r);
	}
	
	public String myReadLine() throws IOException{
		lineNumber++;
		return super.myReadLine();
	}
	
	public void setLineNumber(int lineNumber){
		this.lineNumber = lineNumber;
	}
	
	public int getLineNumber(){
		return lineNumber;
	}
}

三、字節流

    字符流用於操作純文本文件,但在計算機中有些文件不是文本類型的,比如:圖片、mp3、電影等等,這時就要用到字節流操作。字節流的基本操作與字符流相同,但它不僅可以操作字符,還可以操作其他媒體文件。

    字節流的兩個抽象基類:InputStream:,輸入流,相對於內存而言,數據流入到內存中,讀取;OutputStream:輸出流,數據從內存流出到外設中,寫出

    OutputStream類中也有write方法,可是使用的是字節數組,而字符流用的是字符數組

    帶緩衝區的字節流的讀取原理如下圖:


6、複製圖片:

package itheima.day19;

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

//複製一個圖片
public class CopyPic {

	public static void main(String[] args) {
		copyPicture();
	}
	public static void copyPicture(){
		
		FileOutputStream fos = null;
		FileInputStream fis = null;
		try {
			fis = new FileInputStream("抗日英雄:李宗仁.jpg");
			fos = new FileOutputStream("D:\\java\\IODemoFile\\李宗仁:臺兒莊.jpg");
			fos.write("abcd".getBytes());
			
			byte[] buf = new byte[1024];
			int len =0;
			while((len = fis.read(buf))!=-1){
				fos.write(buf,0,len);
			}
		} catch (FileNotFoundException e) {
			throw new RuntimeException("文件未找到異常!");
		} catch (IOException e) {
			throw new RuntimeException("文件讀寫異常!");
		}finally{
			try {
				if(fos!=null)
					fos.close();
			} catch (IOException e) {
				throw new RuntimeException("寫入文件關閉失敗!");
			}
			try {
				if(fis!=null)
					fis.close();
			} catch (IOException e) {
				throw new RuntimeException("讀取文件關閉失敗!");
			}
		}
	}
}

7、複製mp3:

package itheima.day19;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

//複製mp3,通過緩衝區
public class CopyMP3 {

	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		copy_1();
		long end = System.currentTimeMillis();
		System.out.println(end - start+"毫秒");
	}
	public static void copy_1(){
		BufferedInputStream bufis = null;
		BufferedOutputStream bufos = null;
		try {
			bufis = 
					new BufferedInputStream(
							new FileInputStream(
									"D:\\靜心--佛家歌曲\\王菲《心經》第三屆世界佛教論壇.mp3"));
			bufos = 
					new BufferedOutputStream(
							new FileOutputStream("D:\\java\\IODemoFile\\心經.mp3"));
			int by =0;
			while((by = bufis.read())!=-1){
				bufos.write(by);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			
			try {
				if(bufos!=null)
					bufos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			try {
				if(bufis!=null)
					bufis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void copy_2(){
		
		MyBufferedInputStream bufis = null;
		BufferedOutputStream bufos = null;
		try {
			bufis = new MyBufferedInputStream(
						new FileInputStream("D:\\靜心--佛家歌曲\\王菲《心經》第三屆世界佛教論壇.mp3"));
			bufos = new BufferedOutputStream(
						new FileOutputStream("D:\\java\\IODemoFile\\心經11.mp3"));
			int by =0;
			while((by = bufis.myRead())!=-1){
				bufos.write(by);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			
			try {
				if(bufos!=null)
					bufos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			try {
				if(bufis!=null)
					bufis.myClose();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

//模擬BufferedInputStream類
//字節流緩衝區的基本原理:
class MyBufferedInputStream{
	
	private InputStream in;
	private byte[] buf = new byte[1024];
	private int pos =0 ,count = 0;
	MyBufferedInputStream(InputStream in){
		this.in = in;
	}
	
//	爲何返回int 而不是byte?
//	byte -1 ---> int -1(自動類型提升)
// 	1111 1111 --> 1111....1111(32)位
//	很有可能流會讀到連續八個1,返回byte類型的-1,會與結束標識混淆!
	public int myRead() throws IOException{
//		先將數據讀取到字節數組buf中
		if(count ==0){
			count = in.read(buf);
			if(count<0)
	<span style="white-space:pre">	</span>		return -1;
//			一個一個讀取,指針向前,數量減少
			pos =0;
			byte b= buf[pos];
			count--;
			pos++;
			return b&0xff;
		}
		else if(count>0){
			byte b = buf[pos];
			count--;
			pos++;
			return b&0xff;
		}
		return -1;
	}
	
	public void myClose() throws IOException{
		in.close();
	}
}

四、轉換流

    當字節流中的數據都是字符時,轉成字符流操作更加高效。轉換流就是字符流與字節流之間的橋樑,主要是方便字符流與字節流之間的操作。因爲有了字符流之後才需要轉換,所以轉換流定義在字符流體系中。

    InputStreamReader:字節流通向字符流的橋樑;

    OutputStreamWriter:字符流通向字節流的橋樑。

    標準輸入輸出流:在System類中,有兩個字段:in、out,它們分別代表系統標準的輸入和輸出設備;默認的輸入設備對應的是鍵盤,輸出設備對應的是控制檯。System.in的類型是InputStream,System.out的類型是PrintStream;PrintStream是OutputStream的子類。可以通過System.setIn();System.setOut()改變標準輸入輸出設備。

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

8、讀取鍵盤錄入:

package itheima.day19;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;

//讀取鍵盤錄入。
// 		 System.out:對應的設備是標準輸出設備,控制檯。
//		 System.in:對應的設備是標準輸入設備,鍵盤。
//需求:通過鍵盤錄入數據,
//		 當錄入一行數據後,就將改行數據打印
// 		 over,停止錄入。
public class ReadIn {

	public static void main(String[] args) throws IOException {
		
		System.setIn(new FileInputStream("src\\itheima\\day19\\ReadIn.java"));
<span style="white-space:pre">	</span>	System.setOut(new PrintStream("zz.txt"));
		InputStream in = System.in;
		InputStreamReader isr = new InputStreamReader(in);
		BufferedReader bufr = new BufferedReader(isr);
		OutputStream out = System.out;
		OutputStreamWriter osw = new OutputStreamWriter(out);
		BufferedWriter bufw = new BufferedWriter(osw);
		
		String line = null;
		while((line = bufr.readLine())!=null){
			if("over".equalsIgnoreCase(line))
				break;
//			System.out.println(line.toUpperCase());
			bufw.write(line.toUpperCase());
			bufw.newLine();
			bufw.flush();
		}
		bufr.close();
	}
	public static void method_1() throws IOException{
		InputStream in = System.in;
		StringBuilder sb = new StringBuilder();
		
		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);
			}
		}
	}
}

9、異常信息的日誌存儲:

package itheima.day19;

import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;

//異常的日誌信息
public class ExceptionInfoDemo {

	public static void main(String[] args) {
		
		try {
			int[] arr = new int[2];
			System.out.println(arr[3]);
		} catch (Exception e) {
			try {
//				e.printStackTrace(new PrintStream("a.txt"));
//				log4j 專門處理異常日誌的工具包
				
				Date d = new Date();
				SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
				String s = sdf.format(d);
				
				PrintStream ps =new PrintStream("exception.log");
				ps.println(s);
				System.setOut(ps);
				e.printStackTrace(System.out);	
			} catch (FileNotFoundException e1) {
				throw new RuntimeException("日誌文件創建失敗!");
			}
		}
	}
}

    流操作的基本規律:流對象很多,不知道用哪個;可以通過下面三個明確來完成。

    1、明確源和目的,源:輸入流,InputStream、Reader;目的:輸出流,OutputStream

        Writer。

    2、操作的是否是純文本?是:字符流;否:字節流。

    3、當體系明確以後,再明確使用哪個具體的對象,通過設備來進行區分

        源:內存、硬盤、鍵盤;目的:內存、硬盤、控制檯。

    例如:1、將一個文本文件中的數據存儲到另一個文件中:複製文件。

    源:因爲是源,所以使用讀取流。InputStream Reader;是否操作文本文件?是:這時就可以選擇Reader,這樣體系就明確了。

    接下來明確要使用該體系中的那個對象?明確設備:硬盤,上的一個文件。

Reader體系中可以操作文件的對象是FileReader

    是否需要提高效率?

    是,加入Reader體系中的緩衝區BufferedReader

    FileReaderfr = new FileReader(“a.txt”)

    BufferedReaderbufr = new BufferedReader(fr);

    目的:OutputStream Writer ;是否是純文本?是:Writer

    設備:硬盤,一個文件,Writer體系中可以操作文件的對象FileWriter。

    是否需要提高效率?是!加入Writer體系中緩衝區BUfferedWriter

    FileWriterfw = new FileWriter(“b.txt”);

    BufferedWriterbufw = new BufferedWriter(fw);

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