字節流


首先要知道:這四個類是抽象類,是一切字符字節輸入輸出流的父類,因為是抽象類,所以要通過子類來實例化,不能直接實例化;

public abstract class InputStream implements Closeable;
public abstract class OutputStream implements Closeable, Flushable;
public abstract class Reader implements Readable, Closeable;
public abstract class Writer implements Appendable, Closeable, Flushable;

 1)FileInputStream:

    public static void demo1() throws FileNotFoundException, IOException {
        FileInputStream fis = new FileInputStream("xxx.txt");    //創建流對象,個人認為,相當於一根管道
        int x = fis.read();            //從硬盤上讀取一個字節,硬盤上都是以二進制的形式存儲
        System.out.println(x);
        int y = fis.read();
        System.out.println(y);
        int z = fis.read();
        System.out.println(z);
        int a = fis.read();
        System.out.println(a);//文件的結束標志:-1
        int b = fis.read();
        System.out.println(b);
        fis.close();                                            //關流釋放資源
    }

打印的結果為:97、98、99、-1、-1

    /**
     * Reads a byte of data from this input stream. This method blocks
     * if no input is yet available.
   * * *
@return the next byte of data, or <code>-1</code> if the end of the file is reached. * 返回值為0到255的int類型的值,返回值為字符的ACSII值(如a就返回97,n就返回110). * @exception IOException if an I/O error occurs. */ public native int read() throws IOException; //空參構造,返回讀到的內容(第五點闡述有參構造)

 從最基本的開始,假如說相關路徑下有文件"xxx.txt",文件上面有abc三個字母,從上面源碼可以看出,調用一次read()方法,就讀一個字母,返回下一個。結束的時候,就返回-1。

所以可以利用循環來判斷:

    private static void demo2() throws FileNotFoundException, IOException {
        FileInputStream fis = new FileInputStream("xxx.txt");    //創建流對象
        int b;
        //文件的結束標志:-1,所以定義-1就結束了
        while((b = fis.read()) != -1) {
            System.out.println(b);
        }
        fis.close();
    }

read()方法讀取的是一個字節,為什么返回是int,而不是byte(復制的,其實我看不懂)

  因為字節輸入流可以操作任意類型的文件,比如圖片音頻等,這些文件底層都是以二進制形式的存儲的,如果每次讀取都返回byte,有可能在讀到中間的時候遇到111111111,

那么這11111111byte類型的-1,我們的程序是遇到-1就會停止不讀了,后面的數據就讀不到了,所以在讀取的時候用int類型接收,如果11111111會在其前面補上,

240湊足4個字節,那么byte類型的-1就變成int類型的255了這樣可以保證整個數據讀完,而結束標記的-1就是int類型。

2)FileOutputStream:

    public static void demo1() throws FileNotFoundException, IOException {
        //創建字節輸出流對象,如果沒有就自動創建一個
        FileOutputStream fos = new FileOutputStream("yyy.txt");        
        fos.write(97);    //雖然寫出的是一個int數,但是到文件上的是一個字節,會自動去除前三個8位
        fos.write(98);
        fos.write(99);
        fos.close();
    }

 相關路徑的文件"yyy.txt"就在里面寫出了一個abc內容。

如果繼續在上面寫一個,如下:

    public static void demo1() throws FileNotFoundException, IOException {
        //創建字節輸出流對象,如果沒有就自動創建一個
        FileOutputStream fos = new FileOutputStream("yyy.txt");        
//        fos.write(97);    //雖然寫出的是一個int數,但是到文件上的是一個字節,會自動去除前三個8位
//        fos.write(98);
//        fos.write(99);
        fos.write(100);
        fos.close();
    }

 則文件"yyy.txt"上面只會顯示d內容,因為其會在原來的文件上面進行清空,再重新寫。

******在創建對象的時候是如果沒有這個文件會幫我創建出來

******如果有這個文件就會先將文件清空,是將里面的內容清空,再寫入

*****如果不想文件清空,想續寫,則在后面加一個布爾值就可以了。

    private static void demo2() throws FileNotFoundException, IOException {
        FileOutputStream fos = new FileOutputStream("yyy.txt",true);    //如果想續寫就在第二個參數傳true
        fos.write(97);
        fos.write(98);
        fos.close();
    }

 3)拷貝:核心代碼就是下面幾行

    /*
     * 復制文件,圖片,讀一次一個字節,寫一次一個字節
     */
    public static void demo1() throws FileNotFoundException, IOException {
        FileInputStream fis = new FileInputStream("雙元.jpg");        //創建輸入流對象,關聯雙元.jpg
        FileOutputStream fos = new FileOutputStream("copy.jpg");    //創建輸出流對象,關聯copy.jpg
        int b;
        while((b = fis.read()) != -1) {                                //在不斷的讀取每一個字節
            fos.write(b);                                            //將每一個字節寫出
        }
        fis.close();                                                //關流釋放資源
        fos.close();
    }

 一個一個字節去讀,去寫(去拷貝),所以這種方法特別耗時。讀一次寫一次,一共要讀寫900多萬次,所以特別耗時。

4)fis.available()  得到輸入流文件的全部字節數

   /*
     * 不推薦使用,因為有可能會導致內存溢出
     */
    public static void demo3() throws FileNotFoundException, IOException {
        
        FileInputStream fis = new FileInputStream("致青春.mp3");
        FileOutputStream fos = new FileOutputStream("copy.mp3");
        
        byte[] arr = new byte[fis.available()];                    
        fis.read(arr);                                            
        fos.write(arr);                                            
        
        fis.close();
        fos.close();
        
    }

5)

private native int readBytes(byte b[], int off, int len) throws IOException;

//這個方法使用一個byte的數組作為一個緩沖區,每次從數據源中讀取和緩沖區大小(二進制位)相同的數據並將其存在緩沖區中。
//定義的數組長度為10,每次寫進去的也是10
/*
 * 1.從讀取流讀取一定數量的字節,如果比如文件總共是102個字節
 * 2.我們定義的數組長度是10,那么默認前面10次都是讀取10個長度
 * 3.最后一次不夠十個,那么讀取的是2個
 * 4.這十一次,每次都是放入10個長度的數組.
 */
public int read(byte b[]) throws IOException {   
     return readBytes(b, 0, b.length);
}

/*
 * 1.從讀取流讀取一定數量的字節,如果比如文件總共是102個字節
 * 2.我們定義的數組長度是10,但是這里我們寫read(bytes,0,9)那么每次往里面添加的(將只會是9個長度),就要讀12次,最后一次放入3個.
 * 3.所以一般讀取流都不用這個而是用上一個方法:read(byte[]);
 */
public int read(byte b[], int off, int len) throws IOException {   
     return readBytes(b, off, len);
}
 注意:空參構造和有參構造返回的值內容是不一樣

 關於read(byte[] buffer,int off, int len):可以看出:參數buffer表示建了多大長度的緩沖區;off表示把東東往第幾個緩沖區放,所以就一般為0,要知道,為什么不在第0個放,而要浪費第0個的位置呢;len就表示每次往緩沖區放多少個東東;

public static void main(String[] args) throws Exception {         
    InputStream is = null;                                        
    byte[] buffer = new byte[5];                                  
    char c;                                                       
                                                                  
    try {                                                         
        is = new FileInputStream("test.txt");// 里面的內容為:ABCDEFGHI  
        is.read(buffer, 1, 2);                                    
        for (byte b : buffer) {                                   
            if (b == 0) {                                         
                c = '-';                                          
            } else {                                              
                c = (char) b;                                     
            }                                                     
            System.out.print(c);                                  
        }                                                         
        System.out.println();                                     
        is.read(buffer, 1, 3);                                    
        for (byte b : buffer) {                                   
            if (b == 0) {                                         
                c = '-';                                          
            } else {                                              
                c = (char) b;                                     
            }                                                     
            System.out.print(c);                                  
        }                                                         
    } catch (Exception e) {                                       
        e.printStackTrace();                                      
    } finally {                                                   
        if (is != null)                                           
            is.close();                                           
    }                                                             
}                                                                 

 

輸出:

-AB--
-CDE-

    public static void demo1() throws FileNotFoundException, IOException {
        //xxx.txt   文件內容上面為  97,98,99
        FileInputStream fis = new FileInputStream("xxx.txt");
        byte[] arr = new byte[2];
        int a = fis.read(arr);    //將文件上的字節讀取到字節數組中,
                                //返回的是讀到的數組的長度,也就是讀到的字節的個數
        System.out.println("a:"+a);                        //讀到的有效字節個數
        for (byte b : arr) {                        //第一次獲取到文件上的a和b
            System.out.println(b);
        }
        
        int c = fis.read(arr);
        System.out.println(c);
        for (byte b : arr) {
            System.out.println(b);
        }
        fis.close();
    }

 打印出:

2、97、98
1、99、98

標准代碼:

    public static void demo2() throws FileNotFoundException, IOException {
        FileInputStream fis = new FileInputStream("xxx.txt");
        FileOutputStream fos = new FileOutputStream("yyy.txt");
        
        byte[] arr = new byte[2];
        int len;
        while((len = fis.read(arr)) != -1) {   //結合上面的,其實第二次返回的長度等於1了
            fos.write(arr,0,len);              //這次每兩個字節兩個字節地讀,比一開始一個個字節讀快多了
        }                                      //但是在實際中,字節數組長度設置得更大
        
        fis.close();
        fos.close();
    }

 

 我們設置數組長度,就等於我們自己拿着籃子去買菜了,但是實際上在java中,java已經幫我們備好籃子了

private static int defaultBufferSize = 8192;   //每次讀取8192個字節

public BufferedInputStream(InputStream in) {  //包裝,裝飾者模式
    this(in, defaultBufferSize);            
}                                           

public BufferedInputStream(InputStream in, int size) {         
    super(in);                                                 
    if (size <= 0) {                                           
        throw new IllegalArgumentException("Buffer size <= 0");
    }                                                          
    buf = new byte[size];                                      
}                                                              

* E.小數組的讀寫和帶Buffered的讀取哪個更快?

* 定義小數組如果是8192個字節大小和Buffered比較的話

* 定義小數組會略勝一籌,因為讀和寫操作的是同一個數組

* Buffered操作的是兩個數組

     * close方法
     * 具備刷新的功能,在關閉流之前,就會先刷新一次緩沖區,將緩沖區的字節全都刷新到文件上,再關閉,
     * close方法刷完之后就能寫了
     * 只有滿了才刷新,有點不厚道
     *
     * flush方法?
     * 具備刷新的功能,刷完之后還可以繼續寫,自動刷新啊 。。用戶體驗

 字節數組處理中文:

public static void demo1() throws FileNotFoundException, IOException {
    FileInputStream fis = new FileInputStream("yyy.txt");             
    byte[] arr = new byte[4];                                         
    int len;                                                          
    while((len = fis.read(arr)) != -1) {    //寫中文隨時出現亂碼                             
        System.out.println(new String(arr,0,len));//碼表轉中文,string的構造方法                   
    }                                                                                                                                       
    fis.close();                                                      
}                                                                     
public static void main(String[] args) throws IOException {
    //demo1();                                             
    FileOutputStream fos = new FileOutputStream("zzz.txt");
    fos.write("我讀書少,你不要騙我".getBytes()); //字節流寫出中文,要轉換                   
    fos.write("\r\n".getBytes());  //換行                        
    fos.close();                                           
}                                                          

 

 標准代碼:但是實際上一般都不會寫得那么麻煩(1.6版本)

public static void demo1() throws FileNotFoundException, IOException {
    FileInputStream fis = null;  //作用域問題,所以要放在外面                      
    FileOutputStream fos = null;  //如果下面兩兩端代碼初始化失敗                    
    try {                                                             
        fis = new FileInputStream("xxx.txt");                         
        fos = new FileOutputStream("yyy.txt");                        
                                                                      
        int b;                                                        
        while((b = fis.read()) != -1) {                               
            fos.write(b);                                             
        }                                                             
    }finally {   //一定要關流,所以finally                                    
        try{    //如果初始化失敗,沒有開啟,則不用關閉                                  
            if(fis != null)                                           
                fis.close();                                          
        }finally {            //try fianlly的嵌套目的是能關一個盡量關一個              
            if(fos != null)                                           
                fos.close();                                          
        }                                                             
    }                                                                 
}                                                                     

 

1.7 版本之后流自動關閉,全實現了AutoCloseable接口,自動調用里面的close方法(這種方式開發中用得比較少)

//當把流寫在小括號里面,流就會自動關閉,為什么請見下面
public
static void main(String[] args) throws IOException { try( FileInputStream fis = new FileInputStream("xxx.txt"); FileOutputStream fos = new FileOutputStream("yyy.txt"); ){ int b; while((b = fis.read()) != -1) { fos.write(b); } } }
public class FileInputStream extends InputStream;

public abstract class InputStream implements Closeable;

public interface Closeable extends AutoCloseable;

/**
 * A resource that must be closed when it is no longer needed.
 *
 * @author Josh Bloch
 * @since 1.7
 */
public interface AutoCloseable;

 

 

 

 

 

END!

 

 

 

END!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM