EleventhDay--Java基礎(九)I/O流、File類

I/O流
 字節輸入流:InputStream類爲所有字節輸入流的父類
  三個基本的read()方法:
         int read()
          從流裏讀出的一個字節。不推薦使用
         int read(byte[] b)
          將數據讀入到字節數組中,並返回所讀的字節數
         int read(byte[] b, int off, int len)
          off  從哪裏開始讀。
          len  讀取多少。
          將輸入流中最多 len 個數據字節讀入字節數組。
  其它方法:
         void close()
          關閉此輸入流並釋放與該流關聯的所有系統資源。
         int available()
          返回不受阻塞地從此輸入流讀取的字節數。
         long skip(long n)
          跳過和放棄此輸入流中的n個數據字節,該方法有可能失效。
         boolean markSupported()
          測試此輸入流是否支持 mark 和 reset 方法。
         void mark(int n)
          在此輸入流中標記當前的位置
         void reset()
          將此流重新定位到對此輸入流最後調用 mark 方法時的位置。
 
 字節輸出流:OutputStream類是所有字節輸入流的父類
  三個基本的write()方法:
   void write(int n)
    將指定的字節寫入此輸出流。
   void write(byte[] b)
    將 b.length 個字節從指定的字節數組寫入此輸出流。
   void write(byte[] b, int off, int len)
    將指定字節數組中從偏移量off開始的len個字節寫入此輸出流。
  其它方法:
   void close()
          關閉此輸出流並釋放與此流有關的所有系統資源。
   void flush()
          刷新此輸出流並強制寫出所有緩衝的輸出字節。
          
 文件輸入輸出流:FileInputStream和FileOutputStream
  要構造一個FileInputStream,所關聯的文件必須存在而且是可讀的。
   如:
    FileInputStream fis = new FileInputStream("myfile.dat");
  要構造一個FileOutputStream,而輸出文件已經存在,則它將被覆蓋。    
   如:   
       FIleOutputStream fos = new FileOutputStream("results.dat");
      要想以追加的方式寫,則需要一個額外的參數,如:
    FileOutputStream outfile = new FileOutputStream("results.dat" ,true); //參數爲true時輸出爲追加,爲false時爲覆蓋。 

 


 流的概念:程序與數據來源之間的橋樑
 
 流的分類:
  按數據方向分:輸入流和輸出流
    輸入流:InputStream/Reader
    OutputStream/Writer
  按數據類型分:字節流和字符流
   字節流:InputStream/OutputStream
   字符流:Reader/Writer
  按流的功能分:節點流和處理流
   節點流用操作數據的來源。
   處理流用來封裝節點流,從而給節點流增加一個功能,不能獨立存在,在關閉流時如果使用了處理流,只需關閉最外層的流就可以了。
   區分節點流和處理流的小方法:
    看構造器,節點流參數爲數據來源,而處理流參數爲其他流。
 
 選擇流的思路:
  先考慮是輸入流還是輸出流,
  再考慮是字節流還是字符流,
  最後考慮是節點流還是處理流。
  
 字符流:Reader和Writer所有字符流的父類型
  Java技術使用Unicode來表示字符串和字符,而且提供16位版本的流,以便用類似的方法處理字符。
  如果構造了一個連接到流的Reader和Writer,轉換規則會在使用缺省平臺所定義的字節編碼和Unicode之間切換。
  
 橋樑流:InputStreamReader和OutputStreamWriter(字節流轉化成字符流的橋轉換器)
  這兩個類不是用於直接輸入輸出的,他是將字節流轉換成字符流的橋轉換器,並可以指定編解碼方式。
   
 逐行讀寫流:BufferedReader/BufferedWriter
  以上兩個都是過濾流,需要用其他的節點流來作參數構造對象。
  BufferedReader的方法:readLine():String ,當他的返回值是null時,就表示讀取完畢了。要注意,再寫入時要注意寫換行符,否則會出現阻塞。
  BufferedWriter的方法:newLine() ,這個方法會寫出一個換行符。
  
 管道流:線程交互的時候使用
  PipedInputStream/PipedOutputStream
   傳送輸出流可以連接到傳送輸入流,以創建通信管道。傳送輸出流是管道的發送端。通常,數據由某個線程寫入 PipedOutputStream 對象,並由其他線程從連接的 PipedInputStream 讀取。
  注意:管道輸出流和管道輸入流需要對接。
   
 數據流:DataInputStream和DataOutputStream
  通過流來讀寫Java基本類,注意DataInputStream和DataOutputStream的方法是成對的。
  支持直接輸出輸入各種數據類型。
  注意:使用DataOutputStream/DataInputStream時,要注意寫入順序和讀取順序相同,否則會將沒有分割寫入的信息分割不正確而讀取出錯誤的數據。
  
 Properties類:針對屬性文件(*.properties,內容是name=value)進行操作,在java.util包下 
  load(InputStream inStream)
            從輸入流中讀取屬性列表(鍵和元素對)。
           getProperty(String key)
            用指定的鍵在此屬性列表中搜索屬性。
 
 java編碼方式:
  編碼:把字符轉換成數字存儲到計算機中,按ASCII將字母映射爲整數。
  解碼:把數字從計算機轉換成相應的字符的過程。 
  
  不同的國家有不同的編碼,當編碼方式和解碼方式不統一時,產生亂碼。
  因爲美國最早發展軟件,所以每種的編碼都向上兼容ASCII 所以英文沒有亂碼。
   ASCII(英文)                 1個字符佔一個字節(所有的編碼集都兼容ASCII)
   ISO8859-1(拉丁文)     1個字符佔一個字節
   GB-2312/GBK            1個字符佔兩個字節(多用於中文)
   Unicode                1個字符佔兩個字節(網絡傳輸速度慢)
   UTF-8                  變長字節,對於英文一個字節,對於漢字兩個或三個字節。
   
  中文編碼時出現亂碼的情況:
   用流操作文件。
   網頁(動態靜態)。
   網絡傳遞消息。
   
  解決亂碼的方式:
   String temp = 亂碼的字符串
   temp = new String(temp.getBytes("ISO8859-1") , "GBK")  
    將temp按照ISO8859-1的方式進行解碼生成一個字節序列,然後在按照GBK的方式解碼字節序列生成字符串。
  
 File類:可表示文件或者目錄
  File下的方法是對磁盤上的文件進行磁盤操作,但是無法讀寫文件的內容。

  構造器:
   File(String pathname) //以文件的路徑做參數
   
  File類的方法:
   boolean createNewFile()
    創建一個新文件
   File createTempFile(String prefix, String suffix, File directory)
              在指定目錄中創建一個新的空文件,使用給定的前綴和後綴字符串生成其名稱。會在前綴和後綴之間加一個隨機數
   boolean mkdir()
    創建一個新目錄
   boolean delete()
    刪除文件,刪除的是創建File對象時指定與之關聯創建的那個文件。
   String[] List()
    返回當前File對象下所有顯文件和目錄名(相對路徑)
   File[] ListFiles()
    返回當前File對象(必須是目錄)下的所有File對象,可以用getName()來訪問到文件名。
   boolean isDirectory()和boolean isFile()
    判斷究竟是目錄還是文件。
   boolean exists()
    判斷文件或文件夾是否存在。
   String getPath()
    獲得相對路徑。
   String getAbsolutePath()
    獲得文件的絕對路徑
  
  注意:
   File類的對象實施表示一個文件並不是真正的文件,只是一個代理而已,通過這個代理來操作文件
   創建一個文件對象和創建一個文件在java中是兩個不同的概念。前者是在虛擬機中創建了一個文件,但卻並沒有將它真正地創建到OS的文件系統中,隨着虛擬機的關閉,這個創建的對象也就消失了。而創建一個文件纔是在系統中真正地建立一個文件。
   例如:
    File f=new File(“11.txt”); //創建一個名爲11.txt的文件對象
    f.CreateNewFile();      //真正地創建文件

 RandomAccessFile:
  允許隨機訪問文件,類支持直接輸出輸入各種數據類型。
  
  構造器:
   RandomAccessFile(File file, String mode)
             創建從中讀取和向其中寫入(可選)的隨機存取文件流,該文件由 File 參數指定。
   RandomAccessFile(String name, String mode)
             創建從中讀取和向其中寫入(可選)的隨機存取文件流,該文件具有指定名稱。
    mode( r:以只讀方式打開      rw:可讀可寫,不存在則創建)

  相關方法:
   long getFilePointer()
    返回文件指針的當前位置。
   void seek(long pos)
    設置文件指針到給定的絕對位置。
   long length()
    返回文件的長度。   
    
 對象流:ObjectInputStream和ObjectOutputStream(實現對象序列化)
  對象流是過濾流,需要節點流作參數來構造對象,用於直接把對象寫入文件和從文件中讀取對象。
  只有實現了Serializable接口的類型的對象纔可以被讀寫,Serializable接口是個標記接口,其中沒有定義方法。
  對象會序列化成一個二進制代碼,文件中保存對象的屬性。
  
  writeObject(o)、readObject()這兩個是對象讀寫操作時用的方法。
   Object o = new Object(); 
   FileOutputStream fos=new FileOutputStream("Object.txt");
   ObjectOutputStream oos=new ObjectOutputStream(fos);
   oos.writeObject(o);
   oos.close();

   FileInputStream fis =new FileInputStream(“Object.txt”);
   ObjectInputStream ois =new ObjectInputStream(fis);
   Object o = (Object)Ois.readObject();
   ois.close();

  一個類中有其他類型的對象,那麼,這個類實現了Serializable接口,在對象序列化時,也同樣要求這個類中屬性都能夠對象序列化(基本類型除外)。
  
  注意:
   對於對象流的操作,在寫對象時要一次寫入完畢,如果使用追加模式寫入,只會讀取到上一次寫入的對象,使用對象流寫入時,會先寫入一個頭部,然後寫入數據,最後加上結束符號,如果使用追加方式寫入的話,那就會在結束符號繼續向下寫入,但是在讀取時只會讀到結束符爲止,以後再次寫入的數據就會丟失。

 

對象流:ObjectInputStream和ObjectOutputStream
  對象流是過濾流,需要節點流作參數來構造對象,用於直接把對象寫入文件和從文件中讀取對象。
  只有實現了Serializable接口的類型的對象纔可以被讀寫,Serializable接口是個標記接口,其中沒有定義方法。
  對象會序列化成一個二進制代碼。
  
  writeObject(o)、readObject()這兩個是對象讀寫操作時用的方法。
   Object o = new Object(); 
   FileOutputStream fos=new FileOutputStream("Object.txt");
   ObjectOutputStream oos=new ObjectOutputStream(fos);
   oos.writeObject(o);
   oos.close();

   FileInputStream fis =new FileInputStream("Object.txt");
   ObjectInputStream ois =new ObjectInputStream(fis);
   Object o = (Object)ois.readObject();
   ois.close();
  
  transient只能用來修飾屬性。表示這個屬性在對象序列化時將被忽略。
   transient int num;
   表示當我們進行序列化時忽略這個屬性。

  注意:
   對於對象流的操作,在寫對象時要一次寫入完畢,如果使用追加模式寫入,只會讀取到上一次寫入的對象。使用對象流寫入時,會先寫入一個頭部,然後寫入數據,最後加上結束符號,如果使用追加方式寫入的話,那就會在結束符號繼續向下寫入,但是在讀取時只會讀到結束符爲止,以後再次寫入的數據就會丟失。
   包名、類名和屬性可以被序列化,方法和構造器不會被序列化的。
   靜態屬性不會被序列化的。
   屬性會被遞歸序列化的,也就是一個類中有引用類型的屬性,如果這個屬性對應的類實現了Serializable接口,在對象序列化時,也同樣會對這個類中的屬性進行對象序列化,如果沒有實現Serializable接口,則會拋出異常。
   所有屬性必須都是可序列化的,特別是當有些屬性本身也是對象的時候,要尤其注意這一點。
   網絡中傳遞對象必須實現序列化。 
 
nio無阻塞的I/O(優化的I/O) 
 java.nio   定義塊
  Buffer類:一種用於特定的基本類型數據的容器
   緩衝:就是塊,用來存儲內容。
   容量:內存開闢的大小,根據類型的不同,有不同的空間。
   界限:可用部分,即不應讀取或寫入的第一個元素的索引。
   位置:當前指針的位置,從0開始。 
   容量>=界限>=位置
    
   相關方法:
    int capacity()
              返回此緩衝區的容量。
             int limit()
              返回此緩衝區的界限。
             int position()
              返回此緩衝區的位置。
             Buffer flip()
              相當於截斷沒有用的空間,然後把指針移向開頭,使limit=position,position=0
             Buffer position(int newPosition)
              設置此緩衝區的位置。
              
   當有大的文件需要處理的時候,爲了不影響性能建議用直接緩衝。
   Buffer有直接緩衝和間接緩衝兩種。
   只有ByteBuffer類提供了直接緩衝。使用直接緩衝,不影響程序。其它類想用直接緩衝需要進行轉換。
  
 java.nio.channels    對塊進行讀寫的通道,類似於以前的流
  Channel接口:用於 I/O 操作的連接
  
  編程步驟:
   a. 先創建一個I/O流,
   b. 使用I/O流.getChannel()方法,獲得通道,
   c. 創建大小合適的ByteBUffer,
   d. 通道的對象.read(buffer)/write(buffer)進行讀寫,
   e. 關閉所有的流和通道,
   f. 如果有多線程併發,可以使用"通道.lock()"獲得FileLock對象,用FileLock.release() 釋放此鎖定。
   g. 當遇到編碼問題,使用CharSet、CharsetDecoder、CharsetEncoder三個類去解決
   
  注意:
   在讀之前需要調用一下clear()方法,幫助讀操作清理緩衝;寫之前需要調用flip()方法,幫助寫操作清理緩衝。
 
 java.nio.charset    字符集,進行編碼解碼  
  Charset類:編碼類,編碼的信息
   forName(String charsetName)
    生成一個CharSet實例。
   decode(ByteBuffer bb)
             將此 charset 中的字節解碼成 Unicode 字符的便捷方法。
            encode(CharBuffer cb)
             將此 charset 中的 Unicode 字符編碼成字節的便捷方法。
             
  CharsetDecoder類:解碼器
   能夠把特定 charset 中的字節序列轉換成 16 位 Unicode 字符序列的引擎。
   
  CharsetEncoder類:編碼器,編碼的行爲
   能夠把 16 位 Unicode 字符序列轉換成特定 charset 中字節序列的引擎。

        

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