IO流上:概述、字符流、緩衝區(java基礎)
1、IO流概述
概述:html
IO流簡單來講就是Input和Output流,IO流主要是用來處理設備之間的數據傳輸,Java對於數據的操做都是經過流實現,而java用於操做流的對象都在IO包中。java
分類:設計模式
按操做數據分爲:字節流和字符流。 如:Reader和InpurStreamapi
按流向分:輸入流和輸出流。如:InputStream和OutputStream數組
IO流經常使用的基類:緩存
* InputStream , OutputStream網絡
字符流的抽象基類:app
* Reader , Writer函數
由上面四個類派生的子類名稱都是以其父類名做爲子類的後綴:post
如:FileReader和FileInputStream
2、字符流
1. 字符流簡介:
* 字符流中的對象融合了編碼表,也就是系統默認的編碼表。咱們的系統通常都是GBK編碼。
* 字符流只用來處理文本數據,字節流用來處理媒體數據。
* 數據最多見的表現方式是文件,字符流用於操做文件的子類通常是FileReader和FileWriter。
2.字符流讀寫:
注意事項:
* 寫入文件後必需要用flush()刷新。
* 用完流後記得要關閉流
* 使用流對象要拋出IO異常
* 定義文件路徑時,能夠用「/」或者「\\」。
* 在建立一個文件時,若是目錄下有同名文件將被覆蓋。
* 在讀取文件時,必須保證該文件已存在,不然出異常示例1:在硬盤上建立一個文件,並寫入一些文字數據
- class FireWriterDemo {
- public static void main(String[] args) throws IOException { //須要對IO異常進行處理
- //建立一個FileWriter對象,該對象一被初始化就必需要明確被操做的文件。
- //並且該文件會被建立到指定目錄下。若是該目錄有同名文件,那麼該文件將被覆蓋。
- FileWriter fw = new FileWriter("F:\\1.txt");//目的是明確數據要存放的目的地。
- //調用write的方法將字符串寫到流中
- fw.write("hello world!");
- //刷新流對象緩衝中的數據,將數據刷到目的地中
- fw.flush();
- //關閉流資源,可是關閉以前會刷新一次內部緩衝中的數據。當咱們結束輸入時候,必須close();
- fw.write("first_test");
- fw.close();
- //flush和close的區別:flush刷新後能夠繼續輸入,close刷新後不能繼續輸入。
- }
- }
示例2:FileReader的reade()方法.
要求:用單個字符和字符數組進行分別讀取
- class FileReaderDemo {
- public static void main(String[] args) {
- characters();
- }
- /*****************字符數組進行讀取*********************/
- private static void characters() {
- try {
- FileReader fr = new FileReader("Demo.txt");
- char [] buf = new char[6];
- //將Denmo中的文件讀取到buf數組中。
- int num = 0;
- while((num = fr.read(buf))!=-1) {
- //String(char[] value , int offest,int count) 分配一個新的String,包含從offest開始的count個字符
- sop(new String(buf,0,num));
- }
- sop('\n');
- fr.close();
- }
- catch (IOException e) {
- sop(e.toString());
- }
- }
- /*****************單個字母讀取*************************/
- private static void singleReader() {
- try {
- //建立一個文件讀取流對象,和指定名稱的文件關聯。
- //要保證文件已經存在,不然會發生異常:FileNotFoundException
- FileReader fr = new FileReader("Demo.txt");
- //如何調用讀取流對象的read方法?
- //read()方法,一次讀取一個字符,而且自動往下讀。若是到達末尾則返回-1
- int ch = 0;
- while ((ch=fr.read())!=-1) {
- sop((char)ch);
- }
- sop('\n');
- fr.close();
- /*int ch = fr.read();
- sop("ch=" + (char)ch);
- int ch2 = fr.read();
- sop("ch2=" + (char)ch2);
- //使用結束注意關閉流
- fr.close(); */
- }
- catch (IOException e) {
- sop(e.toString());
- }
- }
- /**********************Println************************/
- private static void sop(Object obj) {
- System.out.print(obj);
- }
- }
示例3:對已有文件的數據進行續寫
- import java.io.*;
- class FileWriterDemo3 {
- public static void main(String[] args) {
- try {
- //傳遞一個參數,表明不覆蓋已有的數據。並在已有數據的末尾進行數據續寫
- FileWriter fw = new FileWriter("F:\\java_Demo\\day9_24\\demo.txt",true);
- fw.write(" is charactor table?");
- fw.close();
- }
- catch (IOException e) {
- sop(e.toString());
- }
- }
- /**********************Println************************/
- private static void sop(Object obj)
- {
- System.out.println(obj);
- }
- }
練習:
將F盤的一個文件複製到E盤。
思考:
其實就是將F盤下的文件數據存儲到D盤的一個文件中。
步驟:
1.在D盤建立一個文件,存儲F盤中文件的數據。
2.定義讀取流和F:盤文件關聯。
3.經過不斷讀寫完成數據存儲。
4.關閉資源。源碼:
- import java.io.*;
- import java.util.Scanner;
- class CopyText {
- public static void main(String[] args) throws IOException {
- sop("請輸入要拷貝的文件的路徑:");
- Scanner in = new Scanner(System.in);
- String source = in.next();
- sop("請輸入須要拷貝到那個位置的路徑以及生成的文件名:");
- String destination = in.next();
- in.close();
- CopyTextDemo(source,destination);
- }
- /*****************文件Copy*********************/
- private static void CopyTextDemo(String source,String destination) {
- try {
- FileWriter fw = new FileWriter(destination);
- FileReader fr = new FileReader(source);
- char [] buf = new char[1024];
- //將Denmo中的文件讀取到buf數組中。
- int num = 0;
- while((num = fr.read(buf))!=-1) {
- //String(char[] value , int offest,int count) 分配一個新的String,包含從offest開始的count個字符
- fw.write(new String(buf,0,num));
- }
- fr.close();
- fw.close();
- }
- catch (IOException e) {
- sop(e.toString());
- }
- }
- /**********************Println************************/
- private static void sop(Object obj) {
- System.out.println(obj);
- }
- }
3、緩衝區
1. 字符流的緩衝區:BufferedReader和BufferedWreiter
* 緩衝區的出現時爲了提升流的操做效率而出現的.
* 須要被提升效率的流做爲參數傳遞給緩衝區的構造函數
* 在緩衝區中封裝了一個數組,存入數據後一次取出
BufferedReader示例:
讀取流緩衝區提供了一個一次讀一行的方法readline,方便對文本數據的獲取。
readline()只返回回車符前面的字符,不返回回車符。若是是複製的話,必須加入newLine(),寫入回車符newLine()是java提供的多平臺換行符寫入方法。
- import java.io.*;
- class BufferedReaderDemo {
- public static void main(String[] args) throws IOException {
- //建立一個字符讀取流流對象,和文件關聯
- FileReader rw = new FileReader("buf.txt");
- //只要將須要被提升效率的流做爲參數傳遞給緩衝區的構造函數便可
- BufferedReader brw = new BufferedReader(rw);
- for(;;) {
- String s = brw.readLine();
- if(s==null) break;
- System.out.println(s);
- }
- brw.close();//關閉輸入流對象
- }
- }
BufferedWriter示例:
- import java.io.*;
- class BufferedWriterDemo {
- public static void main(String[] args) throws IOException {
- //建立一個字符寫入流對象
- FileWriter fw = new FileWriter("buf.txt");
- //爲了提升字符寫入效率,加入了緩衝技術。
- //只要將須要被提升效率的流做爲參數傳遞給緩衝區的構造函數便可
- BufferedWriter bfw = new BufferedWriter(fw);
- //bfw.write("abc\r\nde");
- //bfw.newLine(); 這行代碼等價於bfw.write("\r\n"),至關於一個跨平臺的換行符
- //用到緩衝區就必需要刷新
- for(int x = 1; x < 5; x++) {
- bfw.write("abc");
- bfw.newLine(); //java提供了一個跨平臺的換行符newLine();
- bfw.flush();
- }
- bfw.flush(); //刷新緩衝區
- bfw.close(); //關閉緩衝區,可是必需要先刷新
- //注意,關閉緩衝區就是在關閉緩衝中的流對象
- fw.close(); //關閉輸入流對象
- }
- }
2.裝飾設計模式
裝飾設計模式::::
要求:自定義一些Reader類,讀取不一樣的數據(裝飾和繼承的區別)
MyReader //專門用於讀取數據的類
|--MyTextReader
|--MyBufferTextReader
|--MyMediaReader
|--MyBufferMediaReader
|--MyDataReader
|--MyBufferDataReader
若是將他們抽取出來,設計一個MyBufferReader,能夠根據傳入的類型進行加強
class MyBufferReader {
MyBufferReader (MyTextReader text) {}
MyBufferReader (MyMediaReader media) {}
MyBufferReader (MyDataReader data) {}
}
可是上面的類拓展性不好。找到其參數的共同類型,經過多態的形式,能夠提升拓展性
class MyBufferReader extends MyReader{
private MyReader r; //從繼承變爲了組成模式 裝飾設計模式
MyBufferReader(MyReader r) {}
}
優化後的體系:
|--MyTextReader
|--MyMediaReader
|--MyDataReader
|--MyBufferReader //加強上面三個。裝飾模式比繼承靈活,
避免繼承體系的臃腫。下降類與類之間的耦合性
裝飾類只能加強已有的對象,具有的功能是相同的。因此裝飾類和被裝飾類屬於同一個體系
MyBuffereReader類: 本身寫一個MyBuffereReader類,功能與BuffereReader相同
- class MyBufferedReader1 extends Reader{
- private Reader r;
- MyBufferedReader1(Reader r){
- this.r = r;
- }
- //一次讀一行數據的方法
- public String myReaderline() throws IOException {
- //定義一個臨時容器,原BufferReader封裝的是字符數組。
- //爲了演示方便。定義一個StringBuilder容器。最終要將數據變成字符串
- StringBuilder sb = new StringBuilder();
- int ch = 0;
- while((ch = r.read()) != -1)
- {
- if(ch == '\r')
- continue;
- if(ch == '\n') //遇到換行符\n,返回字符串
- return sb.toString();
- else
- sb.append((char)ch);
- }
- if(sb.length()!=0) //當最後一行不是以\n結束時候,這裏須要判斷
- return sb.toString();
- return null;
- }
- /*
- 須要覆蓋Reader中的抽象方法close(),read();
- */
- public void close()throws IOException {
- r.close();
- }
- public int read(char[] cbuf,int off, int len)throws IOException { //覆蓋read方法
- return r.read(cbuf,off,len);
- }
- public void myClose() throws IOException{
- r.close();
- }
- }
1、字節流
1.概述:
一、字節流和字符流的基本操做是相同的,可是要想操做媒體流就須要用到字節流。
二、字節流由於操做的是字節,因此能夠用來操做媒體文件。(媒體文件也是以字節存儲的)
三、讀寫字節流:InputStream 輸入流(讀)和OutputStream 輸出流(寫)
四、字節流操做能夠不用刷新流操做。
五、InputStream特有方法:
int available();//返回文件中的字節個數
注:能夠利用此方法來指定讀取方式中傳入數組的長度,從而省去循環判斷。可是若是文件較大,而虛擬機啓動分配的默認內存通常爲64M。當文件過大時,此數組長度所佔內存空間就會溢出。因此,此方法慎用,當文件不大時,可使用。練習:
需求:複製一張圖片F:\java_Demo\day9_28\1.BMP到F:\java_Demo\day9_28\2.bmp
- import java.io.*;
- class CopyPic {
- public static void main(String[] args){
- copyBmp();
- System.out.println("複製完成");
- }
- public static void copyBmp() {
- FileInputStream fis = null;
- FileOutputStream fos = null;
- try {
- fis = new FileInputStream("F:\\java_Demo\\day9_28\\1.bmp"); //寫入流關聯文件
- fos = new FileOutputStream("F:\\java_Demo\\day9_28\\2.bmp"); //讀取流關聯文件
- byte[] copy = new byte[1024];
- int len = 0;
- while((len=fis.read(copy))!=-1) {
- fos.write(copy,0,len);
- }
- }
- catch (IOException e) {
- e.printStackTrace();
- throw new RuntimeException("複製文件異常");
- }
- finally {
- try {
- if(fis!=null) fis.close();
- }
- catch (IOException e) {
- e.printStackTrace();
- throw new RuntimeException("讀取流");
- }
- }
- }
- }
2. 字節流緩衝區
* 字節流緩衝區跟字符流緩衝區同樣,也是爲了提升效率。
注意事項:
1. read():會將字節byte()提高爲int型值
2. write():會將int類型轉換爲byte()類型,保留最後的8位。
練習:
1.複製MP3文件 1.MP3 --> 2.MP3
2.本身寫一個MyBufferedInputStream緩衝類,提高複製速度
代碼:
- import java.io.*;
- //本身的BufferedInputStream
- class MyBufferedInputStream {
- private InputStream in; //定義一個流對象
- private byte [] buf = new byte[1024*4];
- private int count = 0,pos = 0;
- public MyBufferedInputStream(InputStream in){
- this.in = in;
- }
- public int MyRead() throws IOException{
- if(count==0) { //當數組裏的數據爲空時候,讀入數據
- count = in.read(buf);
- pos = 0;
- byte b = buf[pos];
- count--;
- pos++;
- return b&255; //提高爲int類型,在前面三個字節補充0。避免1111 1111 1111 1111
- }
- else if(count > 0) {
- byte b = buf[pos];
- pos++;
- count--;
- return b&0xff; //提高爲int類型,在前面三個字節補充0。避免1111 1111 1111 1111
- }
- return -1;
- }
- public void myClose() throws IOException{
- in.close();
- }
- }
- class BufferedCopyDemo {
- public static void main(String[] args) {
- long start = System.currentTimeMillis();
- copy();
- long end = System.currentTimeMillis();
- System.out.println("時間:"+(end-start)+"ms");
- start = System.currentTimeMillis();
- copy1();
- end = System.currentTimeMillis();
- System.out.println("時間:"+(end-start)+"ms");
- }
- public static void copy1() { // 應用本身的緩衝區緩衝數據
- MyBufferedInputStream bis = null;
- BufferedOutputStream bos = null;
- try {
- bis = new MyBufferedInputStream(new FileInputStream("馬旭東-入戲太深.mp3"));//匿名類,傳入一個InputStream流對象
- bos = new BufferedOutputStream(new FileOutputStream("3.mp3"));
- int buf = 0;
- while((buf=bis.MyRead())!=-1) {
- bos.write(buf);
- }
- }
- catch (IOException e) {
- e.printStackTrace();
- throw new RuntimeException("複製失敗");
- }
- finally {
- try {
- if(bis!=null) {
- bis.myClose();
- bos.close();
- }
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
2、流操做規律
1. 鍵盤讀取,控制檯打印。
System.out: 對應的標準輸出設備:控制檯 //它是PrintStream對象,(PrintStream:打印流。OutputStream的子類)
System.in: 對應的標準輸入設備:鍵盤 //它是InputStream對象
示例:
- /*================從鍵盤錄入流,打印到控制檯上================*/
- public static void InOutDemo(){
- //鍵盤的最多見的寫法
- BufferedReader bufr = null;
- BufferedWriter bufw = null;
- try {
- /*InputStream ips = System.in; //從鍵盤讀入輸入字節流
- InputStreamReader fr = new InputStreamReader(ips); //將字節流轉成字符流
- bufr = new BufferedReader(fr); */ //將字符流增強,提高效率
- bufr = new BufferedReader(new InputStreamReader(System.in)); //匿名類。InputSteamReader:讀取字節並將其解碼爲字符
- bufw = new BufferedWriter(new OutputStreamWriter(System.out)); //OutputStreamWriter:要寫入流中的字符編碼成字節
- String line = null;
- while((line = bufr.readLine())!=null){
- if("over".equals(line)) break;
- bufw.write(line.toUpperCase()); //打印
- bufw.newLine(); //爲了兼容,使用newLine()寫入換行符
- bufw.flush(); //必需要刷新。否則不會顯示
- }
- if(bufw!=null) {
- bufr.close();
- bufw.close();
- }
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
2. 整行錄入
1.從鍵盤錄入數據,並存儲到文件中。
2. 咱們在鍵盤錄入的是時候,read()方法是一個一個錄入的,能不能整行的錄入呢?這時候咱們想到了BufferedReader中ReadLine()方法。
3. 轉換流
爲了讓字節流可使用字符流中的方法,咱們須要轉換流。
1. InputStreamReader:字節流轉向字符流;
a、獲取鍵盤錄入對象。InputStream in=System.in;
b、將字節流對象轉成字符流對象,使用轉換流。
InputStreamReaderisr=new InputStreamReader(in);
c、爲了提升效率,將字符串進行緩衝區技術高效操做。使用BufferedReader
BufferedReaderbr=new BufferedReader(isr);
//鍵盤錄入最多見寫法
BufferedReaderin=new BufferedReader(new InputStreamReader(System.in));
2.OutputStreamWriter:字符流通向字節流
示例:
- /*================把鍵盤錄入的數據存到一個文件中==============*/
- public static void inToFile() {
- //鍵盤的最多見的寫法
- BufferedReader bufr = null;
- BufferedWriter bufw = null;
- try {
- /*InputStream ips = System.in; //從鍵盤讀入輸入字節流
- InputStreamReader fr = new InputStreamReader(ips); //將字節流轉成字符流
- bufr = new BufferedReader(fr); */ //將字符流增強,提高效率
- bufr = new BufferedReader(new InputStreamReader(System.in)); //匿名類。InputSteamReader:讀取字節並將其解碼爲字符
- bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("out.txt"))); //OutputStreamWriter:要寫入流中的字符編碼成字節
- String line = null;
- while((line = bufr.readLine())!=null){
- if("over".equals(line)) break;
- bufw.write(line.toUpperCase()); //打印
- bufw.newLine(); //爲了兼容,使用newLine()寫入換行符
- bufw.flush(); //必需要刷新。否則不會顯示
- }
- if(bufw!=null) {
- bufr.close();
- bufw.close();
- }
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- }
4. 流操做基本規律
爲了控制格式我將其寫入了Java代碼段中,以下:
示例1:文本 ~ 文本
- /*
- 流操做的基本規律。
- 1、兩個明確:(明確體系)
- 1. 明確源和目的
- 源:輸入流 InputStream Reader
- 目的:輸出流 OutputStream Writer
- 2. 操做的數據是不是純文本
- 是: 字符流
- 否: 字節流
- 2、明確體系後要明確具體使用的對象
- 經過設備區分:內存,硬盤,鍵盤
- 目的設備:內存,硬盤,控制檯
- 示例1:將一個文本文件中的數據存儲到另外一個文件中: 複製文件
- 1、明確體系
- 源:文件-->讀取流-->(InputStream和Reader)
- 是不是文本:是-->Reader
- 目的:文件-->寫入流-->(OutputStream Writer)
- 是否純文本:是-->Writer
- 2、 明確設備
- 源:Reader
- 設備:硬盤上一個文本文件 --> 子類對象爲:FileReader
- FileReader fr = new FileReader("Goods.txt");
- 是否提升效率:是-->加入Reader中的緩衝區:BufferedReader
- BufferedReader bufr = new BufferedReader(fr);
- 目的:Writer
- 設備:鍵盤上一個文本文件 --> 子類對象:FileWriter
- FileWriter fw = new FileWriter("goods1.txt");
- 是否提升效率:是-->加入Writer的緩衝區:BufferedWriter
- BufferedWriter bufw = new BufferedWriter(fw);
- 示例2:將一個圖片文件數據複製到另外一個文件中:複製文件
- 1、明確體系
- 源:文件-->讀取流-->(InputStream和Reader)
- 是不是文本:否-->InputStream
- 目的:文件-->寫入流-->(OutputStream Writer)
- 是否純文本:否-->OutputStream
- 2、 明確設備
- 源:InputStream
- 設備:硬盤上一個媒體文件 --> 子類對象爲:FileInputStream
- FileInputStream fis = new FileInputStream("Goods.txt");
- 是否提升效率:是-->加入InputStream中的緩衝區:BufferedInputStream
- BufferedInputStream bufi = new BufferedInputStream(fis);
- 目的:OutputStream
- 設備:鍵盤上一個媒體文件 --> 子類對象:FileOutputStream
- FileOutputStream fos = new FileOutputStream("goods1.txt");
- 是否提升效率:是-->加入OutputStream的緩衝區:BufferedOutputStream
- BufferedOutputStream bufo = new BufferedOutputStream(fw);
- 示例3:將鍵盤錄入的數據保存到一個文本文件中
- 1、明確體系
- 源:鍵盤-->讀取流-->(InputStream和Reader)
- 是不是文本:是-->Reader
- 目的:文件-->寫入流-->(OutputStream Writer)
- 是否純文本:是-->Writer
- 2、 明確設備
- 源:InputStream
- 設備:鍵盤 --> 對用對象爲:System.in --> InputStream
- 爲了操做方便,轉成字符流Reader --> 使用Reader中的轉換流:InputStreamReader
- InputStreamReader isr = new InputStreamReader(System.in);
- 是否提升效率:是-->加入Reader中的緩衝區:BufferedReader
- BufferedReader bufr = new BufferedReader(isr);
- 目的:Writer
- 設備:鍵盤上一個文本文件 --> 子類對象:FileWriter
- FileWriter fw = new FileWriter("goods1.txt");
- 是否提升效率:是-->加入Writer的緩衝區:BufferedWriter
- BufferedWriter bufw = new BufferedWriter(fw);
5.指定編碼表(轉換流能夠指定編碼表)
要求:用UTF-8編碼存儲一個文本文件
- import java.io.*;
- public class IOStreamLaw {
- /**
- * @param args
- */
- public static void main(String[] args) throws IOException {
- //鍵盤的最多見寫法
- BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
- BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("goods1.txt"),"UTF-8"));
- String line = null;
- while((line=bufr.readLine())!=null){
- if("over".equals(line)) break;
- bufw.write(line.toUpperCase());
- bufw.newLine();
- bufw.flush();
- }
- bufr.close();
- }
- }