總網頁瀏覽量

2013年3月4日 星期一

資料串流、資料讀寫

what:
輸入:將檔案內容由磁碟機讀入後暫存到記憶體內
輸出:將記憶體內暫存資料寫入到檔案中或者將訊息顯示在螢幕上

在java裡面,資料的輸出與輸入皆以串流(stream)的概念進行。串流的資料是由chracters與bit組成。

在處理IO時候要說清楚資料的來源(source)與目的地(sink)

注意stream型態
分成byte stream以及 character stream

byte stream以1byte為單位(位元為主)傳輸資料,長相InputStream/OutputStream;
除了可用於文字檔輸出入之外
也可用於非文字檔(二進位檔案binary file)、圖形檔的輸入輸出

character stream以字元為單位傳輸資料,長相reader/writer
用於文字檔的輸出輸入,避免產生亂碼。


which:

以下IO類別皆放在java.io類別庫之下。
架構如下:

java.io套件:
一、File //管理目錄底下的檔案與目錄。
二、InputStream//以byte為單位輸入
       1.FileInputStream//讀取檔案可讀文字檔也可讀圖檔
       2.ObjectInputStream
三、OutputStream//以byte為單位輸出
       1.FileOutputStream//輸出成檔案
       2.ObjectOutputStream
四、Reader//以字元為單位輸入
       1.InputStreamReader
           a.FileReader
       2.BufferedReader
五、Writer//以字元為單位輸出
       1.OutputStreamWriter
           a.FileWriter
       2.BufferedWriter



一、File



查詢檔名、size、修改日期。
不可存取檔案內容。資料夾也是一種檔案。
File file1 = new File("路徑");
File file2 = new File(File 變數或String 路徑,String 檔案名稱);
list():列出資料夾內的檔名
delete():刪除檔案,如果資料夾內有檔案,必須先刪除

 

 

二、InputStream/OutputStream

1.FileInputStream/FileOutputStream
FileInputStream fis = new FileInputStream("路徑+檔名");
fis.read():以1byte為單位讀取的檔案內容,回傳整數值。
如果沒有讀到任何字元則會回傳-1。

FileOutputStream fos = new FileOutputStream("路徑檔名");
fos.write(int變數或byte陣列);//將檔案內容寫入fos
fos.close();//關閉檔案,如果不關閉會留在記憶體之中

tip:
1.
輸出到文字檔案以附加方式輸出
FileOutputStream fos = new FileOutputStream("路徑檔名",true);
不過用這樣方式輸出圖檔無法以附加方式輸出

2.
int available();//傳回所讀的檔案bytes大小。
這個method是FileInputStream僅有的
可以寫出檔案時事先知道檔案的大小。


  FileInputStream fi=new FileInputStream("D:/java/train.txt");//讀取檔案來源
        System.out.println("file size"+fi.available());//取得檔案大小
        byte ba[]=new byte[fi.available()];//宣告符合檔案大小的byte陣列
    fi.read(ba);//將檔案內容讀到ba
    System.out.println(new String(ba));//轉成字串,列印
    fi.close();


BufferedInputStream/BufferedOutputStream

在記憶體設立緩衝區,批次處理檔案的輸出與輸入,如此一來減少硬碟的讀取次數。
用法:BufferedInputStream bis = new BufferedInputStream(InputStream類別變數或者new InpuStream("路徑檔名"));




FileReader/FileWriter

用法與FileInputStream一樣
英文的文字檔傳輸沒有問題,ANSI檔案的中文字會發生亂碼,UTF8才可以正常輸出,傳輸圖檔會開不起來。


char data[] = new char[128];
    FileReader fr = new
            FileReader("D:\\java\\train.txt");
     int num=fr.read(data);   //將檔案傳入自原陣列,回傳讀的字元數目。
        //ANSI的中文字視為兩個字元(我這個字是為一個字元,UTF8檔案中文視為一個字元)
     System.out.println(num);//列印檔案讀去的字元數
     System.out.println("-------------------------");
     System.out.println(data);//列印陣列的內容
     
String str = new String(data,0,num);
//String(char[],起始點,轉換長度);

System.out.println(str);
//轉換字串後列印結果跟轉換前是一樣的
 
}
}



BufferedReader/BufferedWriter

用法跟BufferedInputStream一樣

BufferedReader除了read()方法之外也可以用
readLine()從檔案抓取文字,一次抓取一行,readLine回傳字串值。

將檔案輸出到新的文字檔並不會自動換行
要用BufferedWriter的方法newLine()才會換行


PrintWriter

官方文件說這是格式化輸出。目前不知道何謂格式化輸出?
句法跟BufferedWrtier一樣,照樣造句
PrintWriter bw1=new PrintWriter(new FileWriter(路徑));
用bw1.println(String變數)
輸出文字到檔案,會自動換行


DataInputStream/DataOutputStream



ObjectInputStream/ObjectOutputStream

以物件型式讀入、讀出資料。

原本資料是物件(ex:在程式碼裡面宣告類別建立物件),以文字型式將資料寫入檔案內,之後取出來便無法以物件方式取出。所以無法直接取得類別的屬性值。

要使用ObjectOutputStream類別將物件寫入檔案,該物件必須是可序列化(serializable)物件。該物件以及該物件內所屬的類別必須實作Serializable介面。否則會產生NotSerializableException事件。
ObjectInputStream則是用反序列化將物件從檔案讀取。
序列化:將物件內所有的屬性以及相關資料依照一定的順序轉成byte型式後寫入檔案。

如果有屬性不想被序列化那麼要在屬性前面加上transient或者static修飾詞。


(將資料輸出檔案用文字編輯器開啟是亂碼,看起來前面部分是描述物件的schema,後面部分是描述個物件的屬性值)

應用:檔案存取、網路資料傳送、影像檔案傳送


範例:
class book implements Serializable{//即將被序列化所以要實作Serializable
String name;//這個name也是物件,類別庫裡面已經實作介面所以我們不用再對他實作
double price;//同上
String author;//同上
public book(String name,double price,String author){
this.name=name;
this.price=price;
this.author=author;
}
public void show(){
System.out.println("書名"+name);
System.out.println("定價"+price);
System.out.println("作者"+author);
}}

File file = new File("D:/temp/kaiba.txt");//隨便準備一個檔案,作為輸出檔案
      book[] books = new book[2];//宣告類別陣列
      books[0]=new book("Conan",100.0,"formosa");
      books[1]=new book("Doraemon",99.9,"FFFF");
   
      FileOutputStream fos = new FileOutputStream(file);//將檔案(file)與OutputStream串接
      ObjectOutputStream oos = new ObjectOutputStream(fos);//串接
      for(Object book:books)//foreach
    oos.writeObject(book);//將物件寫入outputstream,而且被轉換成Object類型
 
      oos.close();
      fos.close();
      //-------------------以下讀取檔案--------------------//
      FileInputStream fis= new FileInputStream(file);//將剛剛的檔案與inputStream串接
      ObjectInputStream ois = new ObjectInputStream(fis);//串接
      System.out.println(file.getName()+"檔案內容如下");
      System.out.println("-----------------");
      try{
    while(true){ 
      ((book)ois.readObject()).show();
//讀取物件並轉換成book(因為讀出的是object物件),並呼叫show method
    }
      }catch(Exception e){
//處理例外,讀到沒有物件時會拋出例外,所以用try catch
      }
      ois.close();
      fis.close();
}

InputStreamReader/OutputStreamWirter

InputStreamReader是byte轉成字元的橋樑。讀取byte轉成字元。
OutputStreamWriter是字元轉成byte的橋樑
轉成什樣字元端看平台的字元預設值。用netbean執行打中文出現亂碼。
因為平台字元預設為utf8處理字元,
我們可以用System.out.println(OSWout.getEncoding());
得知目前用什麼編碼處理字串。
如果處理中文字的話,要加上"big5"指定編碼
InputStreamReader ISRkeyin = new InputStreamReader(InputStream,"big5");
OutputStreamWriter OSWout = new OutputStreamWriter(OutputStream,"big5");
以上兩個缺一不可。


how:
基本操作SOP如下:

1. 指定資料源頭(source)
InputStream keyin = System.in;//源頭來自於使用者鍵盤輸入
InputStreamReader ISRkeyin = new InputStreamReader(keyin,"big5");//byte轉字元。因為System.in是InputStream以byte為單位處理。要丟入以字元為單位處了的buffer所以要轉換。
BufferedReader input = new BufferedReader(ISRkeyin);//字元

2.指定輸出目的地sink
FileOutputStream file = new FileOutputStream("D:/temp/ooxx.txt");//byte完單位
OutputStreamWriter OSWout = new OutputStreamWriter(file,"big5");//字元轉byte
BufferedWriter output = new BufferedWriter(OSWout);

3.
//System.out.println(ISRkeyin.getEncoding());
//System.out.println(OSWout.getEncoding());
String str;
while(( str=input.readLine())!=null) //程式執行到這裡會讓使用者輸入文字,我在這邊又在while這行多打上了分號,結果沒執行下方的程式。
{
if(str.equalsIgnoreCase("Q"))//忽略大小寫,檢查輸入字串
{
input.close();
output.close();
System.exit(-1);//告訴系統結束執行程式。否則仍會繼續執行while,然後拋出例外,也可以打上return ; 也有同樣效果
}

output.write(str);
//OSWout.write(str);//不用buffer也可以將文字輸出到檔案
output.newLine();
System.out.println("你剛才打的文字是:"+str);
}
4.關閉stream
input.close();
output.close();

    }



PS:若省略BufferedReader、BufferedWriter就無法直接讀取輸入String型態的串流\
BufferedReader沒有readLine()

沒有留言:

張貼留言