IO篇

1、IO概述 java

IO是InputOutput的縮寫,IO流即輸入輸出流。
一、IO流:
    1) 用來處理設備之間的數據傳輸。
    2) Java 對數據的操做是經過IO流操做的。
    3) Java用於操做流的對象都在IO包中。
    4) 流只能操做數據。
    5) 流按操做數據分兩種:字節流、字符流;流按流向分爲:輸入流、輸出流。
Note:字符流融合了編碼表,用於處理文字。字節流用於處理圖片、文字,通用的是字節流。程序從輸入流中讀取數據,向輸出流中寫入數據。在數據類型上,read()方法在做提高,write()方法在作強轉,以保證原數據的不變化。
二、IO 流經常使用類:
    字節流的抽象基類:InputStream、OutputStream
    字符流的抽象基類:Reader、Writer
    字符流:FileWriter、FileReader               (字符流緩衝區:BufferedWriter、BufferedReader)
    字節流:FileOutputStream、FileInputStream    (字節流緩衝區:BufferedOutputStream、BufferedInputStream)
Note:由這四類派生出來的子類名稱都是以其父類名做爲子類名的後綴。
    eg:InputStream 的子類 FileInputStream        Reader 的子類 FileReader
linux

2、字符流
字符流是字節流根據指定編碼表編碼而獲得的,因此字符流是在字節流以後出現的。
字符流有如下特色:
    一、字符流中的對象融合了編碼表。默認的編碼,即當前系統的編碼。
    二、字符流只用於處理文字數據,而字節流能夠處理媒體數據。
Writer:寫入字符流的抽象類。
子類必須實現的方法僅有 writer()、flush()、close(),多數子類將重寫方法,以提供更高的效率和其餘功能。IO流是用於操做數據的,而數據的最多見體現形式是文件。查看API,找到一個專門用於操做文件的Writer子類:FileWriter。
一、字符流的讀寫
  a、字符流寫入
步驟:

    1) 建立文件。建立一個 FileWriter 對象,該對象一初始化就必需要明確被操做的文件。並且該文件會被建立到指定的目錄下。若是該目錄下已有同名文件,已有文件將被覆蓋。明確數據要存放的目的地(文件)。
      eg:FileWriter fw=new FileWriter(「demo.txt」);
    2) 調用 writer 方法,將字符串寫入(內存)流中。
      eg:fw.writer(「abcfgggg」);
    3) 刷新流對象中的緩衝區數據。將數據刷新到目的地(文件) 。
      eg:fw .flush();
    4) 關閉流資源(必須有的步驟)。但關閉以前會刷新一次內部緩衝區中的數據,將數據刷新到目的地(文件)。
      eg:fw.close();
flush() 與 close() 的區別:
    flush() 刷新後,流一直存在,能夠繼續寫入數據。
    close() 刷新後會將流關閉,不能再繼續寫入數據。關閉資源須要單獨作 try 處理。
Note:
    1) 其實java自身不能寫入數據,而是調用系統內部方式完成數據的書寫,使用系統資源後,必定要關閉資源。
    2) 文件的數據的續寫是經過構造函數 FileWriter(Strings,boolean append),在建立對象時,傳遞一個true參數,表明不覆蓋已有的文件。並在已有文件的末尾處進行數據續寫。(windows系統中的文件內換行用\r\n兩個轉義字符表示,在linux系統中只用\n表示換行)。
    3) 因爲在建立對象時,須要指定建立文件位置,若是指定的位置不存在,就會發生IOException異常,因此在整個步驟中,須要對IO異常進行try處理。
示例以下:
windows

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

public class FileWriterDemo {

	public static void main(String[] args) {
		// FileWriter(File file) 建立一個file關聯的字符流對象,file對象隨之建立
		Writer file = null;
		try {
			file = new FileWriter("fileWriter.txt");
			// 調用write方法,將字符串寫入字符流中
			file.write("fileDemo");
			// 刷新字符流中的緩衝,將數據刷新到目的地文件中
			file.flush();
			// flush刷新後流資源還可使用,close關閉以後流資源不能訪問
		} catch (IOException e) {
			throw new RuntimeException("文件寫入失敗");
		} finally {
			// 關閉以前判空操做提升效率
			if (file != null) {
				try {
					file.close();
				} catch (IOException e) {
					throw new RuntimeException("文件關閉失敗");
				}
			}
		}
	}
}
b、字符流讀取
步驟:

    1) 建立一個文件讀取流對象,和指定名稱的文件相關聯。要保證該文件已經存在,若不存在,將會發生異常FileNotFoundException,記住要處理異常。
    2) 調用讀取流對象的read()方法,一次讀一個字符,而且會繼續往下讀。
      (第一種方式:讀取單個字符。第二種方式:經過字符數組進行讀取。)
    3) 讀取後要調用close方法將流資源關閉。
示例以下:

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

public class FileReaderDemo {

	public static void main(String[] args) {
		readerMethod_1();
		readerMethod_2();
	}

	public static void readerMethod_2() {
		FileReader fr = null;
		try {
			fr = new FileReader("FileWriterDemo.java");
			// 定義一個字符數組用於存儲讀到的字符
			// read(char[] ch)返貨的是讀到的字符個數
			char[] buf = new char[1024];
			int num = 0;
			// int read(char[] buf) 返回本次讀取到的字符個數
			while ((num = fr.read(buf)) != -1) {
				System.out.print(new String(buf, 0, num));
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (fr != null)
					fr.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public static void readerMethod_1() {
		FileReader fr = null;
		try {
			// 建立一個文件讀取流對象,和指定文件名相關聯
			// 要保證該文件是存在的,不然會報FileNoFoundException
			fr = new FileReader("FileWriterDemo.java");
			int ch = 0;
			// read()一次讀取一個字符
			while ((ch = fr.read()) != -1) {
				System.out.print((char) ch);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (fr != null)
					fr.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
     當咱們讀取文件的時候,上述示例中的第二種方法是先建立了一個字符數組用於存儲讀取到的字符,而後利用read(buf)方法一次讀取多個字符並返回字符個數,這樣一來就比以前的read()方法,每次只讀取一個字符來得要快,其中的字符數組buf就能夠稱爲字符緩衝區。而Java中也提供了字符緩衝區對象。
二、字符流緩衝區
字符流的緩衝區提升了對數據的讀寫效率。
緩衝區對應類:BufferedWriter、BufferedReader。緩衝區要結合流纔可使用,在流的基礎上對流的功能進行加強。緩衝區的出現是爲了提升流的操做效率。所以,在建立緩衝區前,必需要先有流對象。
原理:將數組封裝,變成對象再使用。
BufferedWriter的使用:
步驟:
    1) 建立一個字符寫入流對象。
      eg:FileWriter   w = new FileWriter("buf.txt");
    2) 爲了提升字符寫入流效率,加入緩衝區技術。只要將須要被提升效率的流對象做爲參數傳遞給緩衝區的構造函數便可。
      eg:BufferedWriter   bfw = new BufferedWriter(w);
    3) 寫入數據
      eg:bfw.write(「abc\r\nde」);
    4) 只要用到緩衝區,必須刷新。
      eg:bfw.flush();
    5) 關閉資源。緩衝區的關閉其實就是在關閉提升效率(緩衝區)的流對象。
      eg:bfw.close();
BufferedReader的使用:
    該緩衝區提供了一個一次讀一行的方法readLine,方便於堆文本數據的獲取,當返回null時表示讀到文件末尾。readLine方法返回的時候,只返回回車符以前的數據內容。並不返回回車符。使用步驟:
    1) 建立一個讀取流對象和文件相關聯。
      eg: FileReader bfr=new FileReader(「buf.txt」);
    2) 爲了提升效率,加入緩衝技術。將字符讀取流對象做爲參數傳遞給緩衝對象函數的構造函數。
      eg: BufferedReader bfr=new BufferedReader(bfr);
    3) 讀取緩衝區
      eg: String   line=null;   //記錄讀取的數據
          while((line=bfr.readLine())!=null)   //按行讀取文本內容
          {
               System.out.println(line);
          }
    4) 關閉緩衝區資源。
      eg:  bfr.close();
示例以下:

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

public class CopyTextByBuf {

    public static void main(String[] args) {
        // 定義文件讀取流、輸出流緩衝區
        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            // 將緩衝區關聯文件
            br = new BufferedReader(new FileReader("buf.txt"));
            bw = new BufferedWriter(new FileWriter("copyofbuf.txt"));

            // buf記錄緩衝區讀取到的字符數據
            String buf = null;
            while ((buf = br.readLine()) != null) {
                bw.write(buf);// 向緩衝區中寫入數據
                bw.newLine();// 換行
                bw.flush();// 刷新緩衝區中的數據到目的文件中去
            }
        } catch (IOException e) {
            throw new RuntimeException("文件操做失敗");
        } finally {// 最後關閉資源
            if (bw != null) {
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
LineNumberReader
LineNumberReader是 BufferedReader 的子類,跟蹤行號緩衝字符輸入流。
Note:默認狀況下,行編號從 0 開始。該行號隨數據讀取在每一個行結束符處遞增,並能夠經過調用 setLineNumber(int)更改行號,但並不會實際更改流中的當前位置;它只更改將由 getLineNumber()返回的值。
方法:
setLineNumber(int);    //設置當前行號,能夠設置行號的起點
getLineNumber();    //獲取當前行號
示例以下:

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

public class LineNumberReaderDemo {

    public static void main(String[] args) {

        // 定義字符讀取流
        FileReader fr = null;
        LineNumberReader lnb = null;
        try {
            fr = new FileReader("FileWriterDemo.java");
            // 讓LineNumberReader關聯一個存在的字符讀取流
            lnb = new LineNumberReader(fr);
            String line = null;
            // 設置讀取初始行號爲100
            lnb.setLineNumber(100);
            while ((line = lnb.readLine()) != null) {
                System.out.println(lnb.getLineNumber() + "   " + line);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {// 關閉資源
            if (lnb != null) {
                try {
                    lnb.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
3、字節流
一、簡述:
    1) 字節流和字符流的基本操做是相同的,但字節流還能夠操做其餘媒體文件。
     2) 因爲媒體文件數據中都是以字節存儲,因此字節流對象可直接對媒體文件的數據寫入到文件中,能夠不用再進行刷流動做。
     3) 讀寫字節流:InputStream  輸入流(讀);OutputStream  輸出流(寫)。
     4) 爲什麼不用進行刷流動做:由於字節流操做的是字節,即數據的最小單位,不須要像字符流同樣要進行轉換爲字節。因此可直接將字節數據寫入到指定文件中。
     5) InputStream特有方法:int available();//返回文件中的字節個數
Note: 能夠利用此方法來指定讀取方式中傳入數組的長度,從而省去循環判斷。可是若是文件較大,而虛擬機啓動分配的默認內存通常爲64M。當文件過大時,此數組長度所佔內存空間就會溢出。因此,此方法慎用,當文件不大時,可使用。

示例以下: 數組

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

public class OutputStreamDemo {

    public static void main(String[] args) {
        // fileOutputStream();
        // fileInputStream_1();
        // fileInputStream_2();
        fileInputStream_3();
    }

    // 逐個字節讀取
    public static void fileInputStream_1() {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("fos.txt");
            int ch = 0;
            while ((ch = fis.read()) != -1) {
                System.out.print((char) ch);
            }
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    System.out.println(e.getMessage());
                }
            }
        }
    }

    // 藉助緩衝數組buf,一次讀取多個字節的形式完成文件讀取操做
    public static void fileInputStream_2() {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("fos.txt");
            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = fis.read(buf)) != -1) {
                System.out.println(new String(buf, 0, len));
            }
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    System.out.println(e.getMessage());
                }
            }
        }
    }

    // 藉助特有方法avaliable()返回的文件大小創建一個字節數組,在完成讀取操做
    public static void fileInputStream_3() {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("fos.txt");
            // 獲取待讀取文件的大小
            int numOfChar = fis.available();
            // 建立一個剛恰好的緩衝區
            byte[] buf = new byte[numOfChar];
            int len = 0;
            while ((len = fis.read(buf)) != -1) {
                System.out.println(new String(buf, 0, len));
            }
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    System.out.println(e.getMessage());
                }
            }
        }
    }
    // 字節寫入操做演示
    public static void fileOutputStream() {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("fos.txt");
            fos.write("abcdef".getBytes());
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    System.out.println(e.getMessage());
                }
            }
        }
    }
}
二、字節流緩衝區
讀寫特色

    read():會將字節byte型值提高爲int型值
    write():會將int型強轉爲byte型,即保留二進制數的最後八位。
原理:將數據拷貝一部分,讀取一部分,循環,直到數據所有讀取完畢。
    1)先從數據中抓取固定數組長度的字節,存入定義的數組中,再經過而後再經過read()方法讀取數組中的元素,存入緩衝區。
    2)循環這個動做,直到最後取出一組數據存入數組,可能數組並未填滿,一樣也取出包含的元素。
    3)每次取出的時候,都有一個指針在移動,取到數組結尾就自動回到數組頭部,這樣指針在自增。
    4)取出的時候,數組中的元素在減小,取出一個,就減小一個,直到減到0即元素取完。
    5)當文件中的所有數據都被讀取出時,read()方法就返回-1。
自定義讀取字節流緩衝區
Note:

    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便可。
代碼示例:

/*
 自定義字節流讀取緩衝區
 思路:
 一、定義一個固定長度的數組
 二、定義一個指針和計數器用於讀取數組長度,和計數數組元素是否取完爲0
 三、每次將字節數據存入元素要先將數組中的元素取完
 */
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

class MyBufferedInputStream {
    private InputStream in;
    private byte[] by = new byte[1024];
    private int count = 0, pos = 0;

    MyBufferedInputStream(InputStream in) {
        this.in = in;
    }

    // 自定義讀方法,一次讀一個字節
    public int myRead() throws IOException {
        // 經過in對象讀取硬盤上數據,並存儲by中。
        // 存儲在數組中的數據被讀取完,再經過in對象從硬盤上讀取數據
        if (count == 0) {
            count = in.read(by);
            if (count < 0)// 文件數據所有被讀取出來了
                return -1;

            pos = 0;// 初始化指針
            byte b = by[pos];

            count--;// 每被讀一個字節,表示數組中的字節數少一個
            pos++;// 指針加1
            return b & 255;// 返回的byte類型提高爲int類型,字節數增長,且高24位被補1,原字節數據改變。
                            // 經過與上255,主動將byte類型提高爲int類型,將高24位補0,原字節數據不變。
                            // 而在輸出字節流寫入數據時,只寫該int類型數據的最低8位。
        } else if (count > 0)// 若是數組中的數據沒被讀取完,則繼續讀取
        {
            byte b = by[pos];

            count--;
            pos++;
            return b & 0xff;
        }
        return -1;
    }

    // 自定義關閉資源方法
    public void close() throws IOException {
        in.close();
    }
}

// 測試自定義輸入字節流緩衝區
public class MyBufferedCopyMp3 {
    public static void main(String[] args) {
        // 利用字節流的緩衝區進行復制
        copy();
    }

    // 使用字節流的緩衝區進行復制
    public static void copy() {
        BufferedOutputStream bout = null;
        MyBufferedInputStream bin = null;
        try {
            // 關聯複製文件輸入流對象到緩衝區
            bin = new MyBufferedInputStream(new FileInputStream(
                    "E:\\BaiduMusic\\Songs\\My Love - Westlife.mp3"));
            // 指定文件粘貼位置的輸出流對象到緩衝區
            bout = new BufferedOutputStream(new FileOutputStream(
                    "My Love - Westlife.mp3"));
            int by = 0;

            while ((by = bin.myRead()) != -1) {
                bout.write(by);// 將緩衝區中的數據寫入指定文件中
            }
        } catch (IOException e) {
            throw new RuntimeException("MP3複製失敗");
        } finally {
            try {
                if (bin != null)
                    bin.close();// 關閉輸入字節流
            } catch (IOException e) {
                throw new RuntimeException("讀取字節流關閉失敗");
            }
            try {
                if (bout != null)
                    bout.close();// 關閉輸出字節流
            } catch (IOException e) {
                throw new RuntimeException("寫入字節流關閉失敗");
            }
        }
    }
}
三、轉換流
1) 由來:

    a、字符流與字節流之間的橋樑
    b、方便了字符流與字節流之間的操做
2) 應用:
字節流中的數據都是字符時,轉成字符流操做更高效。
3)InputStreamReader:字節流通向字符流
    a、獲取鍵盤錄入對象。
      InputStream in=System.in;
    b、將字節流對象轉成字符流對象,使用轉換流。
      InputStreamReader isr=new InputStreamReader(in);
    c、爲了提升效率,將字符串進行緩衝區技術高效操做。使用BufferedReader
      BufferedReader br=new BufferedReader(isr);
      //鍵盤錄入最多見寫法
      BufferedReaderin=new BufferedReader(new InputStreamReader(System.in));
4) OutputStreamWriter:字符流通向字節流
    錄入的是字符,存到硬盤上的是字節,步驟和InputStreamReader轉換流基本一致。
四、鍵盤錄入
System.out : 字節流,對應的是標準輸出設備,控制檯。
System.in  : 字節流,對應的是標準輸入設備,鍵盤。
Note: 在 ASCII 碼錶中字符‘\r’對應數字 13 ,‘\n’對應數字10,中止鍵盤錄入:Ctrl+C或者自定義結束標記,通常系統平臺默認的編碼表是 GBK。
System 類中的方法:
    static void setIn(InputStream in)      //從新分配「標準」輸入流
     static void setOut(PrintStream out)    //從新分配「標準」輸出流

示例以下: 網絡

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;

public class ReaderInAndWriterOut {

	public static void main(String[] args) throws IOException {
		InputStreamMethod();
		changeMethod();
	}

	public static void changeMethod() throws IOException {

		// 改變標準輸入輸出流
		System.setIn(new FileInputStream("FileWriterDemo.java"));
		System.setOut(new PrintStream("char.txt"));

		// 獲取鍵盤錄入對象
		InputStream in = System.in;
		// 將字節流轉換成字符流對象使用轉換流InputStreamReader
		InputStreamReader isr = new InputStreamReader(in);
		// 爲提升效率,將字符串進行緩衝區技術的操做使用BufferedReader
		BufferedReader br = new BufferedReader(isr);

		// 簡化書寫以下:
		BufferedReader bufferReader = new BufferedReader(new InputStreamReader(
				System.in));
		BufferedWriter bufferWriter = new BufferedWriter(
				new OutputStreamWriter(System.out));

		// 獲取控制檯輸出 對象
		OutputStream out = System.out;
		OutputStreamWriter osw = new OutputStreamWriter(out);
		BufferedWriter bw = new BufferedWriter(osw);

		String line = null;
		while ((line = br.readLine()) != null) {
			if ("over".equals(line)) {
				break;
			}
			// System.out.println(line.toUpperCase());
			bw.write(line.toUpperCase());
			bw.newLine();
			bw.flush();
		}
		br.close();

	}

	// 自定義鍵盤錄入方法
	public static void InputStreamMethod() throws IOException {
		InputStream in = System.in;
		StringBuilder sb = new StringBuilder();
		int ch = 0;
		while (true) {
			ch = in.read();
			if (ch == '\r') {
				continue;
			}
			if (ch == '\n') {
				String s = sb.toString();
				if (s.equals("over")) {
					break;
				}
				System.out.println(s.toUpperCase());
				// 將緩衝區清空
				sb.delete(0, sb.length());
			} else {
				sb.append((char) ch);
			}
		}
	}
}
五、流操做規律
IO流使用的時候最痛苦的就是流對象有不少,不知道該用哪個,經過三個明確來完成。
1) 明確源和目的。
    源:輸入流。InputStream  Reader
    目的:輸出流。OutputStream  Writer。
2) 操做的數據是不是純文本。
    是:字符流。
    不是:字節流。
3) 當體系明確後,在明確要使用哪一個具體的對象。
    經過設備來進行區分:
    源設備:內存,硬盤。鍵盤
    目的設備:內存,硬盤,控制檯。
例如:將一個文本文件中數據存儲到另外一個文件中。複製文件。
思路分析:
    
    1) 源:由於是源,因此使用讀取流。InputStream Reader 
    是否是操做文本文件。 是!這時就能夠選擇Reader,這樣體系就明確了。
    2) 接下來明確要使用該體系中的哪一個對象。
    明確設備:硬盤。上一個文件。 Reader體系中能夠操做文件的對象是 FileReader
    3) 是否須要提升效率:是!。加入Reader體系中緩衝區 BufferedReader.
    FileReader fr = new FileReader("a.txt");
    BufferedReader bufr = new BufferedReader(fr);
    4) 目的:OutputStream Writer,
    是不是純文本。是!Writer。
    5) 設備:硬盤,一個文件。
    Writer體系中能夠操做文件的對象FileWriter。
    6) 是否須要提升效率:是!。加入Writer體系中緩衝區 BufferedWriter
    FileWriter fw = new FileWriter("b.txt");
    BufferedWriter bufw = new BufferedWriter(fw);
示例以下:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyPic {

	public static void main(String[] args) {
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try {
			fis = new FileInputStream(
					"C:\\Users\\caven\\Desktop\\HeiMa\\IMG_ME.jpg");
			fos = new FileOutputStream("ME1.jpg");
			byte[] buf = new byte[1024];
			int len = 0;
			while ((len = fis.read(buf)) != -1) {
				fos.write(buf, 0, len);
			}
		} catch (IOException e) {
			System.out.println(e.getMessage());
		} finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					System.out.println(e.getMessage());
				}
			}
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					System.out.println(e.getMessage());
				}
			}
		}
	}
}
4、File類
一、File:
文件或者目錄路徑的抽象表示形式。用來將文件或者文件夾封裝成對象,方便文件與文件夾的屬性信息進行操做,File對象能夠做爲參數傳遞給流的構造函數。
成員變量:static String separator    //系統目錄分隔符。與系統有關的默認名稱分隔符,被表示爲一個字符串。
構造函數:
    File(String pathname)    //參數是一個文件。 經過給定路徑名  字符串轉換爲抽象路徑名來建立一個新的 File 實例。
    File(String patent,Stirng child)   //參數左邊是文件父目錄,右邊是子文件。根據父路徑名字符串和子路徑名字符串建立一個新 File 實例。
File對象建立:
    1)將 a.txt 封裝成對象
      File f1=new File("F:\\abc\\a.txt");
    2)左邊指父目錄,右邊指子文件.與 f1 做用同樣。它們的區別是,右邊的子文件是能夠變化的,能夠傳參進去一個變量。
      File f2=new File("F:\\abc","a.txt");
    3)與上面 2 的做用同樣。將文件的父目錄封裝成一個對象,而後做爲參數傳遞
      File d=new File("F:\\abc");
      File f3=new File(d,"a.txt");
    4)實現跨平臺:因爲系統分隔符是分平臺的,爲了體現 java 的跨平臺性,使用File.separator 做爲系統的目錄分隔符
      File f 4=new File("F:"+File.separator+"abc"+File.separator+"a.txt");
經常使用方法:
1) 建立
    boolean createNewFile()  //在指定位置建立文件。若已存在該文件,則返回 false。
                             //與輸出流的區別:輸出流對象一創建就建立文件,若已存在該文件,則會覆蓋。
    createTempFile(String prefix,String suffix); 
    //建立臨時文件,程序使用完會自動刪除或者留存變成垃圾文件。通常臨時文件時以.temp 爲後綴的文件 
    createTempFile(String prefix,String suffix,File directory);  //指定文件路徑,建立臨時文件。
    boolean mkdir()    //建立指定目錄(文件夾) ,只能建立一級目錄
    boolean mkdirs()  //建立指定目錄(文件夾) ,建立多級目錄
2) 刪除
    boolean delete()    //刪除文件或者目錄(文件夾) ,刪除失敗返回 false
    void deleteOnExit()  //在程序退出時刪除文件或者目錄(文件夾)
3) 判斷
    boolean canExecute() //判斷文件是否可執行
    boolean canRead()  //判斷文件是否可讀取
    boolean canWrite()  //判斷文件是否可寫入、修改
    int compareTo(File pathname)    //按字母順序比較兩個文件路徑名
    boolean exists()    //判斷文件或者目錄(文件夾)是否存在
    boolean isDirectory()  //判斷是不是目錄
    boolean isFile()    //判斷是不是文件
Note:判斷文件對象是不是文件或者目錄文件夾時,必須先進行判斷該文件對象封裝的內容是否存在。經過 exists 判斷。
    boolean    isHidden()    //判斷是否爲隱藏文件
    boolean    isAbsolute()  //判斷是否爲絕對路徑,文件不存在也能夠進行判斷
4) 獲取
    String   getName()    //返回文件或者文件夾的名稱
    String    getParent() 
    //獲取父目錄,沒有指定父目錄或者獲取的是相對路徑,則返回 null若相對路徑中有上層目錄,那麼該目錄就是返回結果。
    getPath()        //獲取路徑
    String  getAbsolutePath()    //獲取絕對路徑
    File    getAbsoluteFile()    //獲取絕對路徑,可是是將絕對路徑封裝成對象。
    long  lastModified()      //獲取文件最後一次被修改的時間
    long  length()        //獲取文件的大小
    renameTo()        //重命名
5) 其餘方法
    static File listRoot()   //列出系統中有效盤符。操做共享數據,不操做具體的特有數據。無須建立對象
    String[] list()  
    //返回當前文件夾下的文件以及文件夾名稱。以數組形式列出指定路徑下的全部文件和文件夾(包含隱藏文件)
Note:
    
調用list方法的file對象必須是封裝了一個目錄,該目錄還必須存在。當list所屬對象是一個文件會發生空指針異常。
    String[] list(Filename filter)  //列出指定路徑下的全部指定後綴的文件名
    //list 依據 FilenameFilter 中對象的 accept 方法的返回值來斷定是否須要過濾文件。
    //若返回值爲真,就是全部文件都未過濾,若返回值爲假,則全部文件都被過濾掉。
    FilenameFilter 是一個接口,實現此接口的實例可用於過濾文件名。其中只有一個方法:
    boolean   accept(file dir ,String name )   //dir 表示被過濾的路徑,那麼表示被過濾掉的全部文件名
    File [] listFiles()    //返回當前文件的名稱以及文件夾的對象
Note:能夠經過方法獲取文件名稱、大小、路徑等,開發中經常使用。
示例以下:

import java.io.File;
import java.io.IOException;

/*
 * File類:將文件或者文件夾封裝成對象
 * File常見方法演示:
 */
public class FileDetials {

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		// fileConstructMethod();
		// method_1();
		// method_2();
		// method_3();
		method_4();
	}

	public static void method_4() throws IOException {
		File f = new File("abc\\file.txt");
		System.out.println("createNewFile::" + f.createNewFile());
		System.out.println("path::" + f.getPath());
		System.out.println("AbsolutePath::" + f.getAbsolutePath());
		System.out.println("Parent::" + f.getParent());
		System.out.println("Modified::" + f.lastModified());
		System.out.println("length::" + f.length());
	}

	public static void method_3() throws IOException {
		File f = new File("file.txt");
		// 判斷文件對象是不是文件或者文件目錄以前,必須先判斷文件對象是否存在exists()
		// f.createNewFile();
		// f.delete();
		// f.mkdir();
		System.out.println("isAbsolute::" + f.isAbsolute());
		System.out.println("isHidden::" + f.isHidden());
		System.out.println("file::" + f.isFile());
		System.out.println("dir::" + f.isDirectory());
	}

	public static void method_2() throws IOException {
		File f = new File("FileWriterDemo.java");
		// System.out.println("canExecute::" + f.canExecute());
		System.out.println("exsits::" + f.exists());

	}

	public static void method_1() throws IOException {
		File f = new File("file.txt");
		// 虛擬機退出時刪除文件
		f.deleteOnExit();
		boolean flag1 = f.delete();
		System.out.println("delete::" + flag1);
		boolean flag = f.createNewFile();
		System.out.println("createNewFile::" + flag);

		File dir = new File("abc\\edf");
		System.out.println("mkdir::" + dir.mkdirs());
	}

	// 建立File對象
	public static void fileConstructMethod() {
		// 經過將給定路徑名字符串轉換爲抽象路徑名來建立一個新 File 實例。
		File f = new File("file.txt");
		// 建立指定父目錄下的文件對象
		// File.separator跨平臺的文件分割符
		File fileUnderParent = new File("D:" + File.separator + "JDoc",
				"file.txt");

		System.out.println(f);
		System.out.println(fileUnderParent);
	}

}
5、Properties類
Properties: 
是 Hashtable 的子類。具有了 map 集合的特色,所存儲的鍵值對都是字符串。不須要泛型,是集合中與 IO 技術相結合的集合容器。
特色:能夠用於鍵值對形式的配置文件。在加載數據時,須要數據有固定格式:鍵=值。
Note:  配置文件能夠實現應用程序數據的共享。配置文件只有兩種:properties 或者 xml。在配置屬性文件中,全部前面帶#的信息,都是註釋信息,不會被 properties 加載。
方法:
    load();  //從流中加載鍵值對。注:字符流是從 JDK1.6 版本開始的。早期都是字節流
    list();  //將屬性列表輸出到指定的流中。列出集合目錄
    stringPropertyNames()   //遍歷集合,返回一個 set 集合。 (JDK1.6 版本)
    store()   //設置鍵值對,存到一個流中,並存到文件上。
              //參數:一個是流,另外一個是註釋信息(可不加註釋。註釋沒法解析中文,只能寫英文)
    setProperty()    //設置集合鍵值對,改變的只是內存中的結果
    getProperty(key)    //經過鍵獲取值
示例以下:

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;

public class PropertiesDemo {

	public static void main(String[] args) throws IOException {
		// setAndGet();
		// info2Map();
		loadDemo();
	}
        // 加載設置文件中的信息並修改打印在控制檯
	public static void loadDemo() throws IOException {
		Properties prop = new Properties();
		FileInputStream fis = new FileInputStream("info.txt");
		prop.load(fis);
		// System.out.println(prop);
		FileOutputStream fos = new FileOutputStream("info.txt");
		prop.store(fos, "ok");

		prop.setProperty("lisi", "38");
		prop.list(System.out);
	}

	/*
	 * 需求:將info.txt中的鍵值對數據存入到集合中 一、用一個流對象與文件info.txt關聯 二、讀取一行數據,用「=」進行切割
	 * 三、等號左邊爲鍵,右邊爲值,存入到Properties中
	 */
	public static void info2Map() throws IOException {
		BufferedReader br = new BufferedReader(new FileReader("info.txt"));
		String line = null;
		Properties prop = new Properties();
		while ((line = br.readLine()) != null) {
			String[] datas = line.split("=");
			// prop.put(datas[0],datas[1]);
			prop.setProperty(datas[0], datas[1]);
			// System.out.println(line);
		}
		br.close();
		System.out.println(prop);
	}

	// 設置和獲取元素
	public static void setAndGet() {
		Properties prop = new Properties();
		prop.put("zhangsan", "12");
		prop.put("nihao", "33");
		System.out.println(prop);
		String age = prop.getProperty("nihao");
		System.out.println("age::" + age);

		Set<String> names = prop.stringPropertyNames();
		System.out.println(names);
		for (String name : names) {
			System.out.println(name + ".." + prop.getProperty(name));
		}
	}

}
5、其餘IO類
打印流
:PrintWriter、PrintStream。能夠直接操做輸入流和文件。
序列流:SequenceInputStream。對多個流進行合併。
管道流:PipedInputStream、PipedOutputStream。管道輸入流應該鏈接到管道輸出流
操做對象:ObjectInputStream、ObjectOutputStream。被操做的對象須要實現 Serializable(標記接口);
一、字符打印流
PrintWriter:
是 OutputStream 的子類。常用!爲其餘輸出流添加功能。使其可以方便打印各類數據值表示形式。永遠不會拋出 IOException,異常狀況僅設置可經過checkError 方法測試的內部標誌。
    println()    //打印。能夠對基本數據類型進行直接操做。保證數據原樣性。
    write(int n)    //將指定的字節寫入此流。打印的是 int 類型的最低八位。 
特色:該流提供了打印方法,能夠將各類數據類型的數據都原樣打印。
構造方法:能夠接收的參數類型:file 對象、字符串路徑、字節輸出流(OutputStream) 、字符輸出流(Writer)
二、字節打印流
PrintStream:
爲其餘輸出流添加功能,使它們可以方便地打印數據值表示形式。
Note:
    與其餘輸出流不一樣,永遠不會拋出 IOException ;而是異常狀況僅設置可經過checkError。爲了自動刷新,能夠建立一個 PrintStream,這意味着可在寫入byte數組以後自動調用flush()方法,可調用其中一個 println()方法,或寫入一個換行符或字節('\n')。PrintStream  打印的全部字符都使用平臺的默認字符編碼轉換爲字節。在須要寫入字符而不是寫入字節的狀況下,應該使用PrintWriter  類。
構造方法:能夠接收的參數類型:file 對象、字符串路徑、字節輸出流(OutputStream)
示例以下:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;

/*
 * 打印流:
 */
public class OtherClass {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		PrintWriter pr = new PrintWriter(new BufferedWriter(new FileWriter(
				"a.txt")), true);

		String line = null;
		while ((line = br.readLine()) != null) {
			if ("over".equals(line)) {
				break;
			}
			pr.println(line);
			// pr.flush();
		}
		pr.close();
		br.close();
	}

}
三、序列流
SequenceInputStream: 
 對多個流進行合併。表示其餘輸入流的邏輯串聯。從輸入流有序集合開始,並從第一個輸入流開始讀取,直到到達文件末尾;接着從第二個輸入流讀取,以此類推,直到到達最後一個輸入流的文件末尾爲止。
構造函數:
    SequenceInputStream(s1,s2)    //參數 s1,s2 爲不一樣的輸入流,按順序讀取。
    SequenceInputStream(Enumeration<? extends InputStream> e)
    //經過記住參數來初始化新建立的  SequenceInputStream,該參數必須是生成運行時類型爲InputStream對象的Enumeration型參數(使用此構造要結合集合中枚舉Vector)。
示例以下:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.Enumeration;
import java.util.Vector;

/*
 * 文件合併
 * SequenceInputStream
 * 一、SequenceInputStream(Enumeration en)
 * 二、SequenceInputStream(FileInputStream file1,FileInputStream file2)
 * 
 */
public class SequenceDemo {

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		Vector<FileInputStream> v = new Vector<FileInputStream>();
		v.add(new FileInputStream("1.txt"));
		v.add(new FileInputStream("2.txt"));
		v.add(new FileInputStream("3.txt"));

		Enumeration<FileInputStream> en = v.elements();
		SequenceInputStream sis = new SequenceInputStream(en);

		FileOutputStream fos = new FileOutputStream("4.txt");

		byte[] buf = new byte[1024];
		int len = 0;
		while ((len = sis.read(buf)) != -1) {
			fos.write(buf, 0, len);
		}
		sis.close();
		fos.close();
	}

}
四、管道流
    管道輸入流應該鏈接管道
輸出流,管道輸入流提供要寫入管道輸出流的全部數據字節。
一般數據由某個線程從 PipedInputStream 對象讀取,並由其餘線程將其寫入到相應的PipedOutputStream。不建議對這兩個對象使用單個線程,可能會出現死鎖問題。管道輸入流包含一個
緩衝區,可在緩衝區限定的範圍內將讀操做和寫操做分離開。若向鏈接管道輸出流提供數據字節的線程再也不存在,則認爲該管道已損壞。
構造方法:PipedInputStream()   //建立還沒有鏈接的  PipedInputStream。
方法:connect(PipedOutputStream src)    //使此管道輸入流鏈接到管道輸出流  src。
五、對象序列化流
將堆內存中的對象存入硬盤,保留對象中的數據,稱之爲對象的持久化(或序列化),ObjectOutputStream將java 對象的基本數據類型和圖形寫入 OutputStream。可使用 ObjectInputStream 讀取(重構)對象。經過在流中使用文件能夠實現對象的持久存儲。若流是網絡套接字流,則能夠再另外一臺主機上或另外一個進程中重構對象。只能將支持 java.io.Serializable 接口的對象寫入流中。每一個 Serializable 對象的類都被編碼,編碼內容包括類名和類簽名、對象的字段值和數組值,以及從初始對象中引用的其餘全部對象的閉包。構造函數能夠接收字節流,方法中能夠接收對象。
序列化步驟:
寫入流對象:
    建立對象寫入流,與文件關聯,即傳入目的
    經過寫入writeObject(Object obj)方法,將對象做爲參數傳入,便可寫入文件
讀取流對象
    建立對象讀取流,與文件關聯,即傳入源
    經過readObject()方法,讀取文件中的對象,並返回這個對象
Note:
    靜態成員不能被序列化
    非靜態成員要不被序列化,能夠用關鍵字transient修飾,保證非靜態成員保存在堆內存中,不能存入文件中。
示例以下:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
//建立Peason類,實現Serializable接口
class Person implements Serializable {
    private static final long serialVersionUID = -4461523780114351798L;
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }

    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public Person() {
        super();
    }
}

public class ObjectStreamDemo {

    public static void main(String[] args) throws IOException,
            ClassNotFoundException {
        writeObject();
        readObject();
    }

    // 讀取指定文件中的對象,也稱反序列化
    public static void readObject() throws FileNotFoundException, IOException,
            ClassNotFoundException {
        File file = new File("object.txt");
        if (!file.exists()) {
            return;
        }
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        Person p = (Person) ois.readObject();
        System.out.println(p);
        ois.close();
    }

    // 將指定對象序列化到指定文件中
    public static void writeObject() throws IOException, FileNotFoundException {
        File file = new File("object.txt");
        if (!file.exists()) {
            file.createNewFile();
        }
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
                file));
        oos.writeObject(new Person("zhangsan", 313));
        oos.close();
    }
}

六、字節數組的流:
ByteArrayInputStream和ByteArrayOutputStream

這個對象並無調用底層資源,因此不用關閉流資源,即便關閉後,仍可調用。 內部包含緩衝區,至關於之內存做爲流操做源和目的,不會產生任何IO異常。對象中封裝了數組,其實就是用流的思想操做數組。
構造函數:
        ByteArrayInputStream:在構造函數的時候,須要接受數據源,並且數據源是一個字節數據。
        ByteArrayOutputStream:在構造函數的時候,不用定義數據目的,由於該對象中已經在內部封裝了可變長度的字節數組,這就是數據的目的地。
特有方法:
ByteArrayOutputStream中:
        writeTo(OutputStream out);   //將此 byte數組輸出流的所有內容寫入到指定的輸出流參數中,這與使用out.write(buf, 0, count)調用該輸出流的 write方法效果同樣。由於這個方法用到了字節輸出流,須要拋IO異常,也是字節數組流中惟一須要拋異常的方法。
        int size();   //當前緩衝區的大小
        String toString();   //使用平臺默認的字符集,經過解碼字節將緩衝區內容轉換爲字符串。
示例以下:
閉包

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class ByteArrayStreamDemo {

    @SuppressWarnings({ "unused", "resource" })
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        // 定義一個字節讀取流---數據源
        ByteArrayInputStream bais = new ByteArrayInputStream(
                "ABCDEF".getBytes());
        BufferedInputStream bufIn = new BufferedInputStream(
                new FileInputStream("FileWriterDemo.java"));
        // 字節寫入流---目的
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int len = 0;
        while ((len = bufIn.read()) != -1) {
            baos.write(len);
        }
        System.out.println(baos.size());
        System.out.println(baos.toString());
    }
}
七、字符編碼
簡述

1) 字符流的出現爲了方便操做字符。
2) 更重要的是加入了編碼的轉換,即轉換流。
3) 經過子類轉換流來完成。在兩個對象進行構造的時候,能夠加入字符集(即編碼表)。
可傳入編碼表的有:轉換流 InuputStreamReader和OutputStreamWriter。
                  打印流:PrintStream和PrintWriter(只有輸出流)
4) 編碼表的由來
    計算機只能識別二進制數據,早期由來是電信號。爲了方便應用計算機,讓它能夠識別各個國家的文字。就將各個國家的文字用數字來表示,並一一對應,造成一張表。這就是編碼表。
5) 常見的編碼表:
    ASCII:美國標準信息交換碼錶。用一個字節的7位表示
    IOS8859-1:拉丁碼錶;歐洲碼錶。用一個字節的8位表示
    GB2312:中國的中文編碼表(早期)
    GBK:中國的中文編碼表升級,融合了更多的中文文字字符。打頭的是兩個高位爲1的兩個字節編碼。爲負數
    Unicode:國際標準碼,融合了多種文字。全部文字都用兩個字節來表示,Java語言使用的就是unicode。
    UTF-8:最多用三個字節表示一個字符的編碼表,根據字符所佔內存空間不一樣,分別用一個、兩個、三個字節來編碼。

UTF-8編碼格式:
    一個字節:0開頭
    兩個字節:字節一  ---> 110    位數:10 ~ 6
              字節二  ---> 10     位數:5 ~ 0
    三個字節:字節一  ---> 110    位數:15 ~ 12
              字節二  ---> 10     位數:11 ~ 6
              字節三 ---> 10      位數:5 ~ 0
app

轉換流的編碼應用:
    能夠將字符以指定編碼格式存儲。能夠對文本數據指定編碼格式來解讀。指定編碼表的動做由構造函數完成。
編碼和解碼

1) 編碼:字符串變成字節數組
    默認字符集: String  --->  byte[]  :srt.getBytes()
    指定字符集:String  --->  byte[]  :srt.getBytes(charsetName)
2) 解碼:字節數組變成字符串
    默認字符集: byte[]  --->  String :new String(byte[])
    指定字符集: byte[]   --->  String :newString(byte[],charsetName)
對於編碼和解碼的字符集轉換注意事項
    1) 若是編碼失敗,解碼就沒意義了。
    2) 若是編碼成功,解碼出來的是亂碼,,則需對亂碼經過再次編碼(用解錯碼的編碼表),而後再經過正確的編碼表解碼。針對於IOS8859-1是通用的。
    3) 若是用的是GBK編碼,UTF-8解碼,此時經過再次編碼後解碼的方式,就不能成功了,由於UTF-8也支持中文,在UTF-8解的時候,會將對應的字節數改變,因此不會成功。
    如使用了錯誤的解碼錶: ide


    4) 特別注意:對於中文的」聯通「,這兩個字比較特別,它的二進制位正好是和在UTF-8中兩個字節打頭的相同,因此在文本文件中,若是單獨寫「聯通」或者和知足UTF-8編碼格式的字符一塊兒保存時,記事本就會用UTF-8來進行解碼動做,這樣顯示的就會是亂碼。 函數

    以上所述僅表明我的見解,若有出入請諒解。
相關文章
相關標籤/搜索