Java基礎之IO操作

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/mylizhimin/article/details/8910267

IO概念

IO(Input Output)流用來處理設備之間的數據傳輸
Java對數據的操作是通過流的方式
Java用於操作流的對象都在IO包中
流按操作數據分爲兩種:字節流與字符流。 
流按流向分爲:輸入流,輸出流。

下圖對IO包中的類進行了分類總結


字節流的抽象基類:
InputStream ,OutputStream。
字符流的抽象基類:
Reader , Writer。
注:由這四個類派生出來的子類名稱都是以其父類名作爲子類名的後綴。
如:InputStream的子類FileInputStream。
如:Reader的子類FileReader。

字符流

字符流主要體系結構

    Reader
         |--FileReader
         |--BufferedReader
                  |--LineNumberReader
         |--InputStreamReader

    Writer
         |--FileWriter 
         |--BufferedWriter

         |--OutputStreamWriter

1、FileWriter 

public class FileWriterDemo {
	public static void main(String[] args) throws IOException {
		//創建一個FileWriter對象,該對象一被初始化就必須要明確被操作的文件
		//而且該文件會被創建到指定目錄下。如果該目錄下已有同名文件,將被覆蓋
		//其實該步就是在明確數據存放的目的地
		//如果路徑中有文件夾,則不會自動創建文件夾
		FileWriter fw=new FileWriter("c:\\testjava\\myjava.txt");
		//調用write方法將字符串寫到流中
		fw.write("你好\r");
		//刷新流對象中的緩衝數據,將數據刷到目的地中
		fw.flush();
		//關閉流資源,但是關閉之前會刷新一次內部緩衝中的數據,將數據刷到目的地中
		//和flush的區別:flush刷新後,流可以繼續使用,close刷新後會將流
		fw.close();
	}
}

注意:如果要使文件可以續寫,需要在創建流對象的時候使用

new FileWriter("c:\\testjava\\myjava.txt",true);

2、FileReader

public class FileReaderDemo {
	public static void main(String[] args) throws IOException {
		// 創建一個文件讀取流對象,和指定名稱的文件相關聯
		// 要保證該文件是已經存在的,如果不存在會發生FileNotFoundException
		FileReader fr = new FileReader("c:\\testjava\\myjava.txt");
		// 第一種讀取方式:調用讀取流兌現的read方法,一次讀一個字符
		int ch = 0;
		while ((ch = fr.read()) != -1) {
			System.out.print((char) ch);
		}
		// 第二種讀取方式
		// 定義一個字符數組,用於存儲讀到的字符
		// read(char[])返回的是讀到的字符個數
		char[] len = new char[1024];
		int num = 0;
		while ((num = fr.read(len)) != -1) {
			System.out.println(new String(len, 0, num));
		}
		fr.close();
	}
}

字符流的緩衝區

緩衝區的出現提高了對數據的讀寫效率。
對應類
    BufferedWriter
    BufferedReader
緩衝區要結合流纔可以使用。在流的基礎上對流的功能進行了增強。

BufferedWriter 是Writer的子類 除了有Writer的方法外還有自己特有的方法,如newLine()寫入一個換行符(跨平臺)

public class BufferedWriterDemo {
	public static void main(String[] args) throws IOException {
		//創建一個字符寫入流對象
		FileWriter fw = new FileWriter("c:\\testjava\\myjava.txt");
		//爲了提高字符寫入流效率,加入緩衝技術
		//只需要將需要被提高效率的流對象作爲參數傳遞給緩衝區的構造方法即可
		BufferedWriter bufw=new BufferedWriter(fw);
		bufw.write("dddd");
		bufw.newLine();//換行
		bufw.write("dddd");
		//只要用到緩衝區就要記得刷新
		bufw.flush();
		//關閉緩衝區就是關閉緩衝區中的流對象
		bufw.close();
	}
}

BufferedReader 是Reader的子類 除了有Reader的方法外還有自己特有的方法,如readLine()一次讀取一行,包含該行內容的字符串,不包含任何行終止符,如果已到達流末尾,則返回 null

public class BufferedReaderDemo {
	public static void main(String[] args) throws IOException {
		//創建一個讀取流對象和文件想關聯
		FileReader fr = new FileReader("c:\\testjava\\myjava.txt");
		//爲了提高字符寫入流效率,加入緩衝技術
		//只需要將需要被提高效率的流對象作爲參數傳遞給緩衝區的構造方法即可
		BufferedReader bufr=new BufferedReader(fr);
		String line=null;
		//readLine一次讀一行,當返回null時候說明讀到文件末尾
		while((line=bufr.readLine())!=null){
			System.out.println(line);
		}
		bufr.readLine();
		bufr.close();
	}
}

LineNumberReader是BufferedReader 的子類,是跟蹤行號的緩衝字符輸入流。此類定義了方法setLineNumber(int) 和getLineNumber(),它們可分別用於設置和獲取當前行號。起讀取文件用法和BufferedReader 一樣,只不過在讀取的過程中可以對行號進行操作

裝飾設計模式

概念: 當想要對已有的對象進行功能增強時,可以定義類,將已有對象傳入,基於已有功能,並提供加強功能 那麼自定義的該類稱爲裝飾類
由來:舉例說明
例如現在有如下類的設計用於讀取數據
MyReader//專門用於讀取數據的類。
    |--MyTextReader//用於讀取文本
    |--MyMediaReader//用於讀取媒體
後來發現兩個子類的讀取功能太差,就想引入緩衝技術,從繼承角度思考,我們需要把每一個類分別創建子類,增加緩衝的功能,於是改變其體系結構如下
MyReader//專門用於讀取數據的類。
    |--MyTextReader//用於讀取文本
        |--MyBufferTextReader
    |--MyMediaReader//用於讀取媒體
        |--MyBufferMediaReader
這樣一來 如果MyReader類再有新的子類,我們還要再創建其子類的帶有緩衝功能的子類,如下
MyReader//專門用於讀取數據的類。
    |--MyTextReader//用於讀取文本
        |--MyBufferTextReader
    |--MyMediaReader//用於讀取媒體
        |--MyBufferMediaReader
    |--MyDataReader//用於讀取數據
        |--MyBufferDataReader
不難發現,這樣的體系結構有兩個缺點:1、擴展性極差;2、體系臃腫
於是我們想能不能把帶有緩衝技術的子類抽取出來,做一個公共的類,將需要被緩衝的對象。傳遞進來。也就是,誰需要被緩衝,誰就作爲參數傳遞給緩衝區。這樣繼承體系就變得很簡單。優化了體系結構。

於是寫一個有緩衝功能的類

class MyBufferReader
{
     MyBufferReader(MyTextReader text){}
     MyBufferReader(MyMediaReader media){}
}
發現這樣擴展性很差,於是找到其參數的共同類型,使用多態的形式,提高了程序的擴展性,修改如下
class MyBufferReader extends MyReader
{
         private MyReader r;
         MyBufferReader(MyReader r){}
} 
這裏MyBufferReader就是所謂的裝飾類,之所以要繼承MyReader,裝飾類因爲增強已有對象,具備的功能和已有的是相同的,只不過提供了更強功能。所以裝飾類和被裝飾類通常是都屬於一個體系中的。這樣類的結構就改變爲
MyReader//專門用於讀取數據的類。
         |--MyTextReader
         |--MyMediaReader
         |--MyDataReader
         |--MyBufferReader
裝飾模式比繼承要靈活。避免了繼承體系臃腫。而且降低了類於類之間的關係。

字節流

字節流主要體系結構

    InputStream
         |--FileInputStream
         |--BufferedInputStream

標準鍵盤錄入:System.in
   OutputStream
         |--FileOutputStream
         |--BufferedOutputStream

標準鍵盤輸出:System.out

FileInputStream與FileOutputStream的操作方式

public class FileStreamDemo {
	public static void main(String[] args) throws IOException {
		writeFile();
		readFile_1();
		readFile_2();
		readFile_3();
	}
	//寫入方式
	public static void writeFile() throws IOException {
		FileOutputStream fos = new FileOutputStream("c:\\testjava\\fos.txt");
		fos.write("aaa".getBytes());//寫的時候要將字符串專函成字節數組
		fos.close();
	}
	//第一種讀取方式
	public static void readFile_1() throws IOException {
		FileInputStream fis = new FileInputStream("c:\\testjava\\fos.txt");
		int ch = 0;
		while ((ch = fis.read()) != -1) {//一次讀一個字節
			System.out.print((char) ch);
		}
		fis.close();
	}
	//第二種讀取方式
	public static void readFile_2() throws IOException {
		FileInputStream fis = new FileInputStream("c:\\testjava\\fos.txt");
		byte[] buf = new byte[1024];//定義一個1024byte的緩衝區
		int len = 0;
		while ((len = fis.read(buf)) != -1) {//一次讀一個字節數組
			System.out.print(new String(buf, 0, len));
		}
		fis.close();
	}
	//第三種讀取方式
	public static void readFile_3() throws IOException {
		FileInputStream fis = new FileInputStream("c:\\testjava\\fos.txt");
		byte[] buf = new byte[fis.available()];// 定義一個剛剛好的緩衝區(此方法慎用)
		fis.read(buf);//不需要循環
		System.out.print(new String(buf));
		fis.close();
	}
}

BufferedInputStream與BufferedOutputStream

帶有緩衝區的字節流寫入與讀取對象,使用範例 複製一個Mp3文件到指定路徑

public class CopyMp3 {
	public static void main(String[] args) throws IOException {
		copy_1();
	}

	private static void copy_1() throws IOException {
		BufferedInputStream bufis = new BufferedInputStream(new FileInputStream(
				"C:\\Users\\LiZhimin\\Desktop\\截圖\\許嵩 - 淺唱.mp3"));
		BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream(
				"C:\\Users\\LiZhimin\\Desktop\\截圖\\aaaa.mp3"));
		int len=0;
		while((len=bufis.read())!=-1){
			bufos.write(len);
		}
		bufis.close();
		bufos.close();
	}
}

轉換流

轉換流是字符流操作裏面的對象,是字節流與字符流之間的橋樑

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

通常涉及字符編碼轉換時候需要用到轉換流,因爲在轉換流初始化的時候可以指定編碼表

代碼示例:使用轉換流按行打印鍵盤錄入

public class OutputStreamWriterDemo {
	public static void main(String args[]) throws Exception{
		//獲取鍵盤錄入對象
		InputStream in=System.in;
		//將字節流對象轉換成字符流對象,使用轉換流InputStreamReader
		InputStreamReader isr=new InputStreamReader(in);
		//爲了提高效率,將字符串進行緩衝區技術高效操作,使用BufferedReader
		BufferedReader bufr=new BufferedReader(isr);
		//上面三行代碼可簡化爲
//		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		
		//獲取鍵盤輸出對象
		OutputStream out=System.out;
		//將字符流對象轉換成字節流對象,使用轉換流OutputStreamWriter
		OutputStreamWriter osw=new OutputStreamWriter(out);
		//爲了提高效率,將字符串進行緩衝區技術高效操作,使用BufferedWriter
		BufferedWriter bufw=new BufferedWriter(osw);
		
		//上面三行代碼可簡化爲
//		BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));
		
		String line=null;
		while((line=bufr.readLine())!=null){
			bufw.write(line);
			bufw.newLine();
			bufw.flush();
		}
		bufr.close();
	}
}


流操作的規律
1、明確源和目的
      源:輸入流:InputStream Reader
      目的: 輸出流:OutputStream Writer
2、操作的數據是否是純文本
      是:字符流
      不是:字節流
3、當體系明確後,當明確使用哪個具體的對象
      通過設備來進行區分
      源設備:內存、硬盤、鍵盤
      目的設備、內存、硬盤、控制檯


File類

File類是用來將文件或者文件夾封裝成對象 方便對文件與文件夾的屬性信息進行操作。 File對象可以作爲參數傳遞給流的構造函數。

File類常見方法:
1:創建。
      boolean createNewFile():在指定目錄下創建文件,如果該文件已存在,則不創建。而對操作文件的輸出流而言,輸出流對象已        建立,就會創建文件,如果文件已存在,會覆蓋。除非續寫。
      boolean mkdir():創建此抽象路徑名指定的目錄。
      boolean mkdirs():創建多級目錄。
2:刪除。
      boolean delete():刪除此抽象路徑名錶示的文件或目錄。
      void deleteOnExit():在虛擬機退出時刪除。
      注意:在刪除文件夾時,必須保證這個文件夾中沒有任何內容,纔可以將該文件夾用delete刪除。window的刪除動作,是從裏往外刪。注意:java刪除文件不走回收站。要慎用。
3:獲取.
      long length():獲取文件大小。
      String getName():返回由此抽象路徑名錶示的文件或目錄的名稱。
      String getPath():將此抽象路徑名轉換爲一個路徑名字符串。
      String getAbsolutePath():返回此抽象路徑名的絕對路徑名字符串。
      String getParent():返回此抽象路徑名父目錄的抽象路徑名,如果此路徑名沒有指定父目錄,則返回 null。
      long lastModified():返回此抽象路徑名錶示的文件最後一次被修改的時間。
      File.pathSeparator:返回當前系統默認的路徑分隔符,windows默認爲 “;”。
      File.Separator:返回當前系統默認的目錄分隔符,windows默認爲 “\”。
4:判斷:
      boolean exists():判斷文件或者文件夾是否存在。
      boolean isDirectory():測試此抽象路徑名錶示的文件是否是一個目錄。
      boolean isFile():測試此抽象路徑名錶示的文件是否是一個標準文件。
      boolean isHidden():測試此抽象路徑名指定的文件是否是一個隱藏文件。
      boolean isAbsolute():測試此抽象路徑名是否爲絕對路徑名。
5:重命名。
      boolean renameTo(File dest):可以實現移動的效果。剪切+重命名。
      String[] list():列出指定目錄下的當前的文件和文件夾的名稱。包含隱藏文件。
      如果調用list方法的File 對象中封裝的是一個文件,那麼list方法返回數組爲null。如果封裝的對象不存在也會返回null。只有封裝的對象存在並且是文件夾時,這個方法纔有效。
代碼示例:列出目錄下所有內容(遞歸)
public class DiGui {
	public static void main(String[] args) {
		showDir(new File("E:\\傳智播客\\Java基礎"));
	}

	public static void showDir(File dir) {
		System.out.println(dir);
		File files[] = dir.listFiles();
		for (File f : files) {
			if (f.isDirectory()) {
				showDir(f);
			} else {
				System.out.println(f.getPath());
			}
		}
	}
}

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