java基礎_11_IO流

IO

當程序需要讀取或寫入數據的時候,就會開啓一個數據源的流,這個數據源可以是文件,內存,或是網絡連接。

 

流的分類:

1,按數據方向分:輸入流和輸出流

輸入流:Reader / InputStream

輸出流:Writer / OutputStream

2,按數據類型分:字節流和字符流

字節流:InputStream / OutputStream

|-- FileOutputStream

|-- FileInputStream

緩衝技術

|-- BufferedInputStream 

|-- BufferedOutputStream

字符流:Reader / Writer

|-- FileReader

|-- FileWriter

緩衝技術

|-- BufferedReader    字符讀取流緩衝區

|-- BufferedWriter  字符寫入流緩衝區

轉換流

OutputStreamWriter :將輸出的字符流轉化爲字節流

InputStreamReader :將輸入的字節流轉換爲字符流

例://源,鍵盤

    BufferedReader bufr =  new  BufferedReader(new InputStreamReader(System.in));

注意:不管如何操作,最後都是以字節的形式保存在文件中的。

 

轉換流什麼時候使用?

是字符和字節之間的橋樑,通常,涉及到字符編碼轉換時,需要用到轉換流。

例:

按照指定的編碼表(UTF-8)存到文件中使用下面的方法

BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\123\\d.txt""UTF-8")));

 

管道流

管道輸出流:PiPedOutputStream

管道輸入流:PipedInputStream

打印流

PrintStream

爲其他輸出流添加了功能,使它們能夠方便地打印各種數據值表示形式。它還提供其他兩項功能。與其他輸出流不同,PrintStream 永遠不會拋出 IOException

合併流

SequenceInputStream (Enumeration<? extends InputStream> e)

將多個流合併成一個,然後再輸出到指定位置

例:

將三個文本文件中內容合併成一個文件。

思路:讀取一個文本就會創建一個流。把這些流放在集合中。

   Vector<FileInputStream> v = new Vector<FileInputStream>();

     v.add(new FileInputStream("d:\\123\\1.txt"));
     v.add(new FileInputStream("d:\\123\\2.txt"));
     v.add(new FileInputStream("d:\\123\\3.txt"));

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

    //SequenceInputStream 只接收 Enumeration(枚舉)所以在選用集合時選能實現枚舉的
     SequenceInputStream sis = new SequenceInputStream(en);

     FileOutputStream fos = new FileOutputStream("d:\\123\\123.txt");

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

     fos.close();
     sis.close();

 

操作字節數組的流對象

ByteArrayInputStream   

在構造的時候,需要接收數據源,而且數據源是一個字節數組。

例:

ByteArrayInputStream bis = new ByteArrayInputStream("abcd".getBytes());

 

ByteArrayOutputStream

     在構造時,不用定義數據目的,因爲該對象中已經內部封裝了可變長度的字節數組。

     例:

      ByteArrayOutputStream bos = new ByteArrayOutputStream();

           int by = 0;

while ((by=bis.read())!=-1)

{

  bos.write(by);

}

System.out.println(bos.toString());

操作字符數組

CharArrayReader

CharArrayWriter  用法一樣

操作字符串

StringReader

StringWriter

操作基本數據類型的流對象

DataInputStreamgn 

DataOutputStream

Properties 

操作於集合和IO流之間, Properties 繼承於 Hashtable

 

緩衝區技術

緩衝區的出現是爲了提高流的操作效率而出現的。所以在創建緩衝區之前,必須要先有流對象。

例:

使用寫入流緩衝區技術

//1,創建一個字符寫入流對象

FileWriter fw = new FileWriter("buf.txt");

//2,爲了提高寫入流效率,加入緩衝技術

BufferedWriter bufw = new BufferedWriter(fw);

這樣就可以使用緩衝技術的方法,如:newLine()  換行,使用這個具有跨平臺性。

 

注意: bufw.close();  //底層操作其實就是fw流,所以只要關閉緩衝區就是關閉fw

例:

複製一個Mp3,通過字節流的 緩衝區完成複製

   public void method() throws IOException
   {
    	BufferedInputStream bfis = new BufferedInputStream(new FileInputStream("D:\\123\\Honey.mp3"));
    	BufferedOutputStream bfos = new BufferedOutputStream(new FileOutputStream("D:\\123\\123.mp3"));
     int by = 0;
    	while ( (by=bfis.read()) !=-1 )  
    	{
    	    bfos.write(by);
    	}
    	    bfis.close();
    	    bfos.close();
   } 

例:複製一個圖片,不用緩衝區,使用數組完成,

    public void method2() throws IOException
    {
    	  FileInputStream fis = new FileInputStream("D:\\123\\1.jpg");
    	  FileOutputStream fos = new FileOutputStream("D:\\123\\2.jpg");
    
    	  byte[] buf = new byte[1024];  // 這裏數組其實就相當於是緩衝區
    	  int len = 0;
    	  while ((len=fis.read(buf))!=-1)
    	  {
          fos.write(buf,0,len);
        }
    
    	  fis.close();
       fos.close();
    }

 

自定義緩衝區技術:

實現原理:

使用底層InputStream  read 方法,將數據存入到緩衝區(數組)中,我們從緩衝區讀數據是從數組中讀取數據,當該數組中讀完後,讓read方法在讀一次,把讀到的數據存入到緩衝區中,。。。這樣循環,直到,把數據源中的數據讀完。

 

這裏以定義 字節流緩衝區 爲例

    class MyBufferedInputStream 
    {
    	private InputStream in;
    	private byte[] buf = new byte[1024];  //緩衝區,
    	private int pos = 0,count = 0;  //計數器,指針
    	MyBufferedInputStream(InputStream in) 
    	{
    		this.in = in;
    	}
    	//調用一次 從緩衝區(字節數組)中讀一個字節
    	public int myRead() throws IOException
    	{
    		//通過in對象讀取硬盤上數據,並存儲在緩衝區buf中
    		if(count==0)
    		{
    			count = in.read(buf);  //採用底層方法讀取一批數據存入緩衝區,並返回其個數
    			if(count<0)
    				return -1;
    			pos = 0;   //指針歸位,指向數組0角標開始
    			byte b = buf[pos];   // 指針指向的當前數據
    			count--;
    			pos++;
    			return b&255;  //返回讀取到的數據		
    		}
    		else if(count>0)  //如果緩衝區還有數據,則取緩衝區中的下一個數據,如緩衝區無數據(count=0時)則讓底層read在去讀一批數據存入緩衝區,直到讀完
    		{
    			byte b = buf[pos];
    			count--;
    			pos++;
    			return b&255;			
    		}
    		return -1;
    	}
    	public void myClose() throws IOException  //提供關閉流的方法
    	{
    		in.close();
    	}
    
    } 
    /*
    爲什麼要與255呢?
    	因爲返回類型爲int  而byte會自動提升
    	byte 1111  (-1)提升爲:
    	int  1111 1111 1111 1111 (還是-1)
    
                  前面填充了1使得一開始while ((by=bfis.myRead())!=-1)不滿足沒有進行循環
    	所以得填充0  只要與 0000 0000 0000 1111 進行與運算就能保證填充爲0
    			1111 1111 1111 1111
    		&	0000 0000 0000 1111
    		   ----- -------------------------
    		      0000 0000 0000 1111
*/

 

流對象很多,使用時該用那一個呢?

流操作規律:通過兩個明確來完成。

 

1,明確源和目的。

源:輸入流。 InputStream(字節流)   Reader(字符流)

目的:輸出流。  OutputStream(字節流)  Writer(字符流)

 

2,操作的數據是否是純文本。

是:使用字符流。

不是:使用字節流。

 

1

將一個文本文件中的數據存儲到別一個文件中(複製文件)

 

源: 

用讀取流。InputStream   Reader

是文本文件 選Reader

操作文件對象的是 FileReader

 

要提高效率用:加入緩衝區

FileReader fr = new FileReader("a.txt");

BufferedReader bufr = new BufferedReader(fr);

 

目的: 

用 OutputStream   Writer

是純文本 用Writer

操作文件 FileWriter

 

提高效率用:加入緩衝區

  FileWriter fw = new FileWriter("b.txt");

  BufferedWriter bufw = new BufferedWriter(fw);

 

2

把鍵盤輸入的數據保存到一個文件中。 

 

源:  是純文本,用Reader

設備:鍵盤,對應的對象是System.in(字節流)

爲了操作鍵盤的文本數據方便,轉成字符流按照字符串操作是最方便的

所以將System.in轉換成Reader 即轉換流InputStreamReader

InputStreadmReader isr = new InputStreamReader(System.in);

 

提高效率!->緩衝區

BufferedReader bufr = new BufferedReader(isr);

 

目的:是純文本,用Writer

一個文件,使用FileWriter,當然也可以用OutputStreamWriter

FileWriter fw  = new FileWriter("c.txt");

BufferedWriter bufw = new BufferedWriter(fw);

 

*************************

擴展一下。

想要把錄入的數據按照指定的編碼表(UTF-8)存到文件中

目的:存儲時,需要加入指定編碼表。而指定的編碼表只有轉換流可以指定。

所以要使用的對象是OutputStreamWriter

而該轉換流對象要接收一個字節輸出流。而且還可以操作誰的的字節輸出流FileOutputStream

OutputStreamWriter osw = new OutputStreamWriter( 

new FileOutputStream("d.txt"),"utf-8");

BufferedWriter bufw  = new BufferedWriter(osw);

 

Scanner

可以使用正則表達式來解析基本類型和字符串的簡單文本掃描器

Scanner 使用分隔符模式將其輸入分解爲標記,默認情況下該分隔符模式與空白匹配。然後可以使用不同的 next 方法將得到的標記轉換爲不同類型的值。

      Scanner sc = new Scanner(System.in);

      int i = sc.nextInt();

 

File

用於表示文件(目錄),通過File類操作硬盤上的文件和目錄。File類只用於表示文件的信息(名稱,大小等),不能對文件的內容進行訪問。

注意:File類的兩個常量,如果想實現跨平臺,那麼最好使用下面的方法來代替分隔符

\ : File.separator

; : File.pathSeparator

 

在創建文件時,如果該目錄下已有同名文件,將被覆蓋。在寫入數據的時候記得要將緩衝區的數據刷新到目的地中。

fw.flush();  //刷新流對象中的緩衝區中的數據,將數據刷新到目的地中

           fw.close();  //關閉流資源,但是關閉之前會刷新一次內部的緩衝區中的數據。

      //將數據刷到目的地中。流關閉後,不能在寫入數據。

           closeflush區別:flush刷新後,流可以繼續使用,close刷新後,會將流關閉

例:

//列出指定目錄下的所有文件名稱及其路徑

     public static void method_2()
     { 
    		File f = new File("D:\\123");
    		
    		File s[] = f.listFiles();
    		for(File fi : s)
    		{
    			System.out.println(fi);
    		}
    	}
      //列出指定文件類型的文件(如:列出後綴名爲.java的文件)
    	public static void method_3()
    	{
    		File f = new File("D:\\123");
    
    		File s[] = f.listFiles(new FilenameFilter()
    		{
    			public boolean accept(File dir,String name)
    			{
    				return name.endsWith(".txt");
    			}
    		});
    		for(File fi : s)
    		{
    			System.out.println(fi);
    		}
    }

 

注意:在建立文件時,如果文件存在,繼續往裏面寫入數據,

則傳遞一個true參數,代表不覆蓋已有的文件 ,並在已有文件的末尾進行數據續寫

如:fw = new FileWriter("D:\\123\\demo.txt",true);

文本文件中的換行語句  \r\n 

      FileDialog :選擇文件對話框窗口 

System

System 類包含一些有用的類字段和方法。它不能被實例化。

在 System 類提供的設施中,有標準輸入、標準輸出和錯誤輸出流;對外部定義的屬性和環境變量的訪問;加載文件和庫的方法;還有快速複製數組的一部分的實用方法

 

System.in 默認是指鍵盤錄入,還可以自己指定位置

    使用: System.setIn(InputStream in) ;

                如:System.setIn(new FileReader("123.txt")) ;

    源:就被設置成了一個文件

      System.out 輸出位置也可設置

                 使用:setOut(PrintStream out) ;

                 如:System.setOut(new FileWriter("222.txt")) ;

     目的:輸出位置設置成了一個文件

System.currentTimeMillis(); 返回當前系統時間,以毫秒計算。

 

常見的編碼表

ASCII : 美國標準信息交換碼。用一個字節的7位可以表示

ISO8859-1 :拉丁碼錶。歐洲碼錶。用一個字節的8位表示

GB2312 : 中國的中文編碼表。

GBK :中國的中文編碼表升級,融合了更多的中文文字符號。

Unicode : 國際標準碼,融合了多種文字。

    所有文字都用兩個字節來表示,Java語言使用的就是unicode

UTF-8 : 最多用三個字節來表示一個字符。

注意:聯通兩個字,這兩個字的GBK編碼,UTF-8的規律相似


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