Java字節流和字符流(超雞簡單明瞭的!!!)

字節流和字符流

1流操作簡介

File類不支持文件內容處理,如果要處理文件內容,必須要通過流的操作模式來完成。流分爲輸入流和輸出流。在java.io包中,流分爲兩種:字節流與字符流
字節流(byte):(針對字節的處理,比較底層)InputStream、OutputStream
字符流(char):(針對於字符的處理)Reader、Writer
字節流與字符流的區別只有一個,字節流是原生操作,字符流是處理後的操作。
在進行網絡數據傳輸,磁盤數據保存所保存所支持的數據類型只有:字節。
而所有磁盤中的數據必須先讀取到內存後才能進行操作,而內存中會幫助我們把字節變爲字符。字符更加適合處理中文。

流操作流程:
無論是字符流還是字節流,操作流程幾乎一樣,以文件操作爲例

    1:取得File對象
    2:取得file對象的輸入、輸出流
    3:進行數據的讀取或寫入操作
    4:關閉流(close()).

IO處理屬於資源操作,所有資源處理(IO、數據庫、網絡)使用後都必須關閉。

2、字節輸出流(OutputStream)

如果要想通過程序進行內容輸出,則可以使用java.io.OutoutStream
來觀察OutputStream類的定義結構

public abstract class OutputStream implements Closeable,Flushable

OutputStream類實現了Closeable、Flushable兩個接口,這兩個接口中的方法:

Closeable:public void close() throws IOException;
Flushable:public void flush() throws IOException;

在OutputStream類中還定義有其他方法:

將指定的字節數組全部輸出:public void write(byte[] b)throws IOException;
將部分字節數組輸出:public void write(byte[] ,int offset,int len)throws IOException;
輸出單個字節:public abstract void write(int b)throws IOException;

由於OutputStream是一個抽象類,所以要想爲父類實例化,就必須使用子類。由於方法名稱都由父類聲明好了,所以我們在此處只需要關心子類的構造方法。如果要進行文件的操作,可以使用FileOutputStream類來處理。這個類的構造方法如下:

文件內容覆蓋:public FileOutputStream(File file)throws FileNotFoundException ;
文件內容追加:public FileOutputStream(File file,boolean append);

實現文件的內容輸出:

//實現我們文件內容的輸出
import java.io.*;

public class OutputStreamTest {
    public static void main(String[] args) throws IOException {
        File file=new File("C:"+File.separator+"Users"+File.separator+"白樂榮"+
                File.separator+"Desktop"+File.separator+"Tset.txt");
       //如果文件不存在就創建
        if(!file.getParentFile().exists()){//必須保證父目錄存在
            file.getParentFile().mkdirs();//創建多級目錄
        }
        //OutputStream是一個抽象類,所以需要通過子類進行實例話,此時自能操作File類
        OutputStream outputStream=new FileOutputStream(file);
        //要求輸入到文件的內容
        String msg="我愛編程,我愛java";

        //將內容變爲字節數組
        outputStream.write(msg.getBytes());
        //關閉輸出
        outputStream.close();
    }
}

執行上面的代碼,你將會發現桌面上出現了一個Tset.txt文件,裏面的內容就是我愛編程,我愛Java。
在進行我們文件輸出的時候,所有的文件會自動幫助用戶創建,不需要調用createFile()手工創建。這個程序如果重複執行,並不會出現追加的情況而是一直覆蓋,如果需要文件內容追加,則需要調用FileOutputStream提供的另外一種構造方法。
實現我們的文件內容的追加

//實現我們的追加程序
 import java.io.*;

public class FileAddTest {
    public static void main(String[] args) throws IOException {
        File file=new File("C:"+File.separator+"Users"+File.separator+"白樂榮"+
                File.separator+"Desktop"+File.separator+"Tset.txt");
        //如果文件不存在就創建
        if(!file.getParentFile().exists()){//必須保證父目錄存在
            file.getParentFile().mkdirs();//創建多級目錄
        }
        //OutputStream是一個抽象類,所以需要通過子類進行實例化,此時只能操作File類
        OutputStream outputStream=new FileOutputStream(file,true);
        //要求輸出到文件的內容
        String msg="我愛我自己";
        //將內容變爲字節數組
        outputStream.write(msg.getBytes());
        //關閉輸出
        outputStream.close();
    }
}

我們將上述代碼執行幾遍,就會出現幾次我們的“我愛我自己”。
這就是我們的文件內容追加。
接下來,我們在實現一個文件部分內容輸出的代碼

部分輸出有時會產生亂碼

AutoCloseable的自動關閉支持

從JDK1.7開始追加一個AutoCloseable接口,這個接口的主要目的是自動進行關閉處理,但是這種處理一般不用,因爲它必須結合try…catch

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class TestIO {
public static void main(String[] args) throws Exception{
File file = new File(File.separator + "Users" + File.separator + "白樂榮" +
File.separator + "Desktop"
+ File.separator + "hello.txt");
if (!file.getParentFile().exists()) { // 必須保證父目錄存在
file.getParentFile().mkdirs() ; // 創建多級父目錄
}
// OutputStream是一個抽象類,所以需要通過子類進行實例化,此時只能操作File類
try(OutputStream output = new FileOutputStream(file,true)){
// 要求輸出到文件的內容
String msg = "我愛我自己\n" ;
// 將內容變爲字節數組
output.write(msg.getBytes());
}catch (Exception e) {
e.printStackTrace();
}
}
}

必需要在try的括號裏面調用對象。比較雞肋,一般不建議使用這種方法。

3字節輸入流:(InputStream)

我們已經實現了利用OutputStream將程序內容輸出到文件的處理,下面使用InputStream類在程序中讀取文件內容。

//InputStream類的定義如下:
public abstract class InputStream implements Closeable

發現InputStream類只實現了Closeable接口,在InputStream類中提供有入下方法:
1、讀取數據到字節數組中,返回數據的讀取個數。如果此時開闢的字節數組大小大於讀取的數據大小,則返回的就是讀取個數;如果要讀取的數據大於數組內容,那麼這個時候返回的就是數組長度;如果沒有數據了還在讀,則返回-1:public int read(byte b[])throws IOException.最常用的方法
2、讀取部分數據到字節中,每次只讀取傳遞數組的部分內容,如果讀取滿了則返回長度(len),如過沒有讀取滿則返回讀取的數據個數,如果讀到最後沒有數據了返回-1:public int ready(byte b[],int off,int len)throws IOException
3、讀取單個字節,每次讀取一個字節的內容明知道沒有數據了返回-1:public abstract int read()throws IOException;
同OutputStream的使用一樣,InputStream是一個抽象類,如果要對其實例化,同樣也需要使用子類,如果文件進行處理,則使用FileInputStream類。

import java.io.*;

public class PartOutTest {
    public static void main(String[] args) throws IOException {
    //定義文件路徑
        File file=new File("C:"+File.separator+"Users"+File.separator+"白樂榮"+
                               File.separator+"Desktop"+File.separator+"Tset.txt");
       //必須保證文件存在才能進行處理
        if(file.exists()){
            InputStream inputStream=new FileInputStream(file);
            byte[] data=new byte[1024];
            int len=inputStream.read(data);
            //將數據讀取到字符數組中,這個字符數組相當於一個緩衝區
            String result=new String(data,0,len);
            System.out.println("讀取內容【"+result+"】");
            inputStream.close();
        }
    }
}

我們從我們的整個操作流程可以發現OutputStream、InputStream類的使用形式上是非常類似的。

流程整理
  1:取得File對象
  2:取得file對象的輸入、輸出流
  3:進行數據的讀取或寫入操作
  4:關閉流(close()).

4、字符輸出流:(Writer)

字符適合於處理中文數據,Writer是字符輸出流的處理類,這個類的定義如下:

public abstract class writer implements Appendable,Closeable,Flushable

與我們的OutputStream相比多了一個Appendable接口
在Writer類裏面也提供write()方法,而且該方法接收的類型都是char型,要注意的是,Writer類提供了一個直接輸出字符串的方法:

//直接輸出字符串
public void write(String str) throws IOException

如果要操作文件使用FileWriter子類

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

public class WriterTest {
    public static void main(String[] args) throws IOException {
    //取得文件對象
        File file=new File("C:"+File.separator+"Users"+File.separator+"白樂榮"+
                File.separator+"Desktop"+File.separator+"Hello.txt");
                //如果文件不存在,就創建
       if(!file.getParentFile().exists()){
           file.getParentFile().mkdirs();
       }
       
        String msg="我愛我家";
        //獲取輸出流
        Writer writer=new FileWriter(file);
        //寫入文件
        writer.write(msg);
        //關閉流
        writer.close();
    }
}

Writer類的結構與方法的使用與OutputStream非常相似,只是Writer類對於中文的支持很好並且提供了直接寫入的String的方法而已。

5、字符輸入流:Reader

Reader依然也是一個抽象類。如過要進行文件讀取,同樣的,使用FileReader。
Writer類中提供有方法直接向目標元寫入字符串,而在Reader類中沒有方法可以直接讀取字符串類型,這個時候只能通過字符數組進行讀取操作。

import java.io.*;

/*
* 這是一個將文件內容讀取到輸入流的程序
* */
public class ReadTest {
    public static void main(String[] args) throws IOException {
        File file=new File("C:"+File.separator+"Users"+File.separator+"白樂榮"+
                File.separator+"Desktop"+File.separator+"Hello.txt");
     //取得文件按後保證文件存在
       if(file.exists()){
           //獲取輸入流
           Reader in=new FileReader(file);
           char [] data=new char[1024];
           int len=in.read(data);
           //進行數據讀取
           String result=new String(data,0,len);
           System.out.println("讀取內容【"+result+"】");
           in.close();
       }
    }
}

6、字節流VS字符流

使用字節流和字符流在代碼的形式上差距不大,但是在實際的開發過程中,字節流一定是優先考慮的只有在處理中文的時候纔會考慮字符流。因此所有的字符都需要通過內容緩衝來進行處理。所有的字符都需要通過內存緩衝來進行所有字符流的操作,無論寫入還是輸出,數據都先保存在緩存中。

//如果字符流不關閉,數據就有可能保存在緩存中沒有輸出到目標元。這種情況下就必須強制刷新才能夠得到完整的數據。
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

/*
* 字符流的刷新操作*/
public class FlushTest {
    public static void main(String[] args) throws IOException {
        File file=new File("C:"+File.separator+"Users"+File.separator+"白樂榮"+
                File.separator+"Desktop"+File.separator+"Hello.txt");
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        String msg="我愛你";
        Writer out=new FileWriter(file);
        out.write(msg);
        out.flush();//表示強制清空緩衝內容,所有內容輸出
    }
}

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