JAVA---字節流

目錄

寫入數據

讀數據

示例:

字節流的緩衝區

自定義字節流緩衝區

緩衝區中read和write的特點


寫入數據

FileoutputStram

class FileStream
{
    public static void writeFile() throws IOException
    {
        FileOutputStream fos = new FileOutputStream("fos.txt")
        //寫入需要轉化爲字節
        fos.write("abc".getBytes());
        //
        fos.close()
    }
}

 

讀數據

//一個字節一個字節的讀
class FileStream
{
    public static void ReadFile_1() throws IOException
    {
        FileInputStream fos = new FileInputStream(fos.txt);
        
        int ch=0;
        while((ch=fis.read())!=-1)
        {
            System.out.println((char)ch);
        }
    }
}
//一個數組的讀
class FileStream
{
    public static void ReadFile_1() throws IOException
    {
        FileInputStream fos = 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));
        }

        fis.close();
    }
}

 

拿到文件大小

class FileStream
{
    public static void ReadFile_3() throws IOException
    {
        FileInputStream fos = new FileInputStream(fos.txt);
        
        //available返回了文件中數據的個數(回車符算2個,/r/n)
        byte[] buf =new byte[fis.available()]; //定義一個剛剛好的緩衝區,不用在循環了
        
        fis.read(buf);

        System.out.println(new String(buf));
        
        fis.close();
    }
}

1,字符流在底層調用了字節流的緩衝區,所以需要刷新動作;而字節流在操作時則不需要刷新
2,available()方法要慎用,虛擬機內存默認爲64M,如果只用一個大小剛好的緩衝數組,在copy較大的文件時顯然是無法承受的,數據太大容易發生內存溢出,

建議用byte[] buf =new byte[1024];

1.因爲現代操作系統的內存管理都具有分頁機制,而內存頁的大小都是1024的整數倍,定義1024整數倍大小的緩衝區在分配內存時將不會形成碎片。

2.讀和寫都是放在while循環中的,每次讀取1024個字節,也就是1kb,如果最後一次讀取和寫入可能不夠1024個字節,所以寫入的時候加了fos.write(buf,0,len);意思是還剩多少就寫多少。

 

示例:

複製一個圖片

/*
思路:
1.用字節讀取流對象和圖片關聯
2.用字節寫入流對象創建一個圖片文件,用於存儲獲取到的圖片數據
3.通過循環讀寫,完成數據的存儲
4.關閉資源
*/
class CopyPic
{
    public static void main(Stirng[] args)
    {
        FileOutputStream fos =null;
        FileInputStream fis=null;

        try
        {
            fos = new FileOutputStream("C:\\2.bmp");
            fis = new FileInputStream("C:\\1.bmp");

            byte[] buf = new byte[1024];

            int len=0;
            while(len=fis.read(buf)!=-1)
            {
                fos.write(buf,0,len);
            }
        }
        catch(IOException e)
        {
            throw new RuntimeException("複製文件失敗");
        }
        finally
        {
            try
            {
                if(fis!=null)
                    fis.close();
            }
            catch(IOException e)
            {
                throw new RuntimeException("讀取關閉失敗");
            }

            try
            {
                if(fos!=null)
                    fos.close();
            }
            catch(IOException e)
            {
                throw new RuntimeException("寫入關閉失敗");
            }
        }    
    }
}

 

字節流的緩衝區

class Copy
{
    public static void main(String[] args) throws IOException
    {
        //計算運行copy方法需要多長時間
        long start = System.currentTimeMillis();
        copy();    
        long end = System.currentTimeMillis();

        System.out.println((end-start)+"毫秒")
    }

    //通過字節流的緩衝區完成複製
    public static void copy throws IOException
    {
        BufferedInputStream bufis =new BufferedInputStream(new FileInputStream("C:\\0.mp3"));
        BufferedOutputStream bufis =new BufferedOutputStream(new FileOutputStream("C:\\1.mp3"));

        int by =0;
        while(by =bufis.read()!=-1)
        {
            bufos.writer(by);
        }    

        bufos.close();
        bufis.close();
    }
}

 

自定義字節流緩衝區

import java.io.*;
class MyBufferedIOStream 
{
	private InputStream in;//裝飾模式,私有化成員變量
	private byte[] buf = new byte[1024];	//1,定義數組
	private int pos = 0, count = 0;			//2,定義指針pos、3,定義計數器count表示數組中剩餘元素個數
	MyBufferedInputStream(InputStream in){	//裝飾類構造函數
		this.in = in;
	}
	public int myRead() throws IOException	//自定義字節流緩衝區read方法,一次讀取一個字節,
	{	
		if (count == 0)	//計數器爲0,則讀取一個數組,開始計數
		{	//通過in對象讀取硬盤上數據,存儲到buf數組中
			count = in.read(buf);//read返回該數組中有效元素個數,到末尾返回-1
			if (count<0)	//健壯性判斷、read到達文件末尾返回爲-1
				return -1;	
			pos = 0;	//執行到這一步說明有一個新的數組,初始化指針
			byte b = buf[pos];//通過指針獲取字節數組元素
			count--;	//執行一次,元素有效個數-1
			pos++;		//指針位置右移
			return b&255;	//該數組字節爲byte,通過&與運算將其提升爲int型並補上24個0返回
		}
		else if (count>0)	//計數器大於0,對數組繼續讀取就可以了
		{
			byte b = buf[pos];
			count--;
			pos++;
			return b&0xff;	//16進制的255
		}
	}
	public static void main(String[] args) 
	{
		System.out.println("Hello World!");
	} 
}

緩衝區中read和write的特點

在計算機中數據都是以二進制存取的,而字節是以byte型存取的

如果剛好有連續的8個1,直接轉成int型就還是-1,而在緩衝區中的read時,就意外滿足了-1的控制條件

從而導致讀寫操作無法進行,所以字節流緩衝區的read方法必須避免這種情況的發生生

byte: -1  --->  int : -1;

00000000 00000000 00000000 11111111  255

11111111 11111111 11111111 11111111

11111111  -->提升了一個int類型 那不還是-1嗎?是-1的原因是因爲在8個1前面補的是1導致的。

那麼我只要在前面補0,即可以保留原字節數據不變,又可以避免-1的出現。

怎麼補0呢?

   通過&運算補0

11111111 11111111 11111111 11111111                       

&00000000 00000000 00000000 11111111

------------------------------------

00000000 00000000 00000000 11111111 

 

結論:

字節流的讀一個字節的read方法爲什麼返回值類型不是byte,而是int。

因爲有可能會讀到連續8個二進制1的情況,8個二進制1對應的十進制是-1;那麼就會數據還沒有讀完,就結束的情況。因爲我們判斷讀取結束是通過結尾標記-1來確定的。

所以,爲了避免這種情況將讀到的字節進行int類型的提升。並在保留原字節數據的情況前面了補了24個0,變成了int類型的數值。

而在write寫入數據時,只寫該int類型數據的最低8位,write有強制轉換爲byte,保證了數據的原樣性

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