1. 程式人生 > >Java FileInputStream/FileOutputStream的應用 檔案讀取和寫入

Java FileInputStream/FileOutputStream的應用 檔案讀取和寫入

這是一對繼承於InputStream和OutputStream的類,用於本地檔案讀寫(二進位制格式讀寫並且是順序讀寫,讀和寫要分別創建出不同的檔案流物件);

本地檔案讀寫程式設計的基本過程為:

①  生成檔案流物件(對檔案讀操作時應該為FileInputStream類,而檔案寫應該為FileOutputStream類);

②  呼叫FileInputStream或FileOutputStream類中的功能函式如read()、write(int b)等)讀寫檔案內容;

③  關閉檔案(close())。

例項:流檔案讀寫

流檔案的單元是位元組,所以它不但可以讀寫文字檔案,也可以讀寫圖片、聲音、影像檔案,這種特點非常有用,因為我們可以把這種檔案變成流,然後在網路上傳輸。

問題是有了通用的流檔案以後,為什麼還要專門的字元流呢?這是因為文字可以用不同的方式儲存,可以是普通的文字(UTF-8編碼方式),ASCII文字和Unicode文字,字元流物件可以進行必要的轉換,從而讀出正確的文字。

有人認為流檔案不能讀寫文字檔案,這其實是個誤會,因為文字檔案本質上也是由位元組組成的,當然是流檔案的一種。作為讀寫檔案的全體,這是沒問題的,但是,如果要處理每次讀入的內容,就最好使用字元流。

所以在文字檔案處理時,使用字元流是個最常用的方法。

樣例:

import java.io.*;

public class FileStreamDemo {

public static void main(String[] args) throws IOException {

//建立兩個檔案,face.gif是已經存在檔案,newFace.gif是新建立的檔案

File inFile = new File("face.gif");

File outFile = new File("newFace.gif");

//建立流檔案讀入與寫出類

//    網上下載:

//    URL url = new URL("http://pic12.nipic.com/20101215/6437485_092856093811_2.jpg");
//    HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
//    InputStream is = urlConnection.getInputStream();
////    //FileInputStream is=new FileInputStream("獲取路徑");//下載本地路徑可用
//    File file= new File("存放路徑");
//    FileOutputStream fos = new FileOutputStream(file);
//    int i=0;  
//    while((i=is.read())!=-1){
//     fos.write(i);
//    }
//    is.close();
//    fos.close();

  1. 檔案不存在
  2. if(!file.exists())    
  3. {    
  4.     try {    
  5.         file.createNewFile();    
  6.     } catch (IOException e) {    
  7.         // TODO Auto-generated catch block  
  8.         e.printStackTrace();    
  9.     }    
  10. }    
  1. //件夾不存在則建立  
  2. if  (!file .exists()  && !file .isDirectory())      
  3. {       
  4.  System.out.println("//不存在");  
  5. file .mkdir();    
  6. }

FileInputStream inStream = new FileInputStream(inFile);

FileOutputStream outStream = new FileOutputStream(outFile);

//通過available方法取得流的最大字元數

byte[] inOutb = new byte[inStream.available()];

inStream.read(inOutb);  //讀入流,儲存在byte陣列

outStream.write(inOutb);  //寫出流,儲存在檔案newFace.gif中

inStream.close();

outStream.close();

}

}

例項:讀寫任意大檔案應用

因為byte陣列最大儲存值不超過64M,所以當一個檔案大於60M 的時候,需要分開幾個流操作。我們把上面的程式作一個修改,就可以寫入任意大小的檔案。這個程式應用了FileInputStream類的方法如下:

read(byte[] b,int off,int len)

把特定位置的流內容讀入陣列,已經讀入byte[]陣列的內容,會在流檔案中刪除。

程式執行的結果會產生一個新檔案。

樣例:

import java.io.*;

public class FileStreamDemo2 {

public static void main(String[] args) throws IOException {

//建立兩個檔案

File inFile = new File("tcty36.rm");

File outFile = new File("newtcty36.rm");

//最大的流為60Mb,當檔案的容量大於60Mb的時候便分開流

final int MAX_BYTE = 60000000;

long streamTotal = 0;  //接受流的容量

int streamNum = 0;  //流需要分開的數量

int leave = 0;  //檔案剩下的字元數

byte[] inOutb;  //byte陣列接受檔案的資料

//建立流檔案讀入與寫出類

FileInputStream inStream = new FileInputStream(inFile);

FileOutputStream outStream = new FileOutputStream(outFile);

//通過available方法取得流的最大字元數

streamTotal = inStream.available();

//取得流檔案需要分開的數量

streamNum = (int)Math.floor(streamTotal/MAX_BYTE);

//分開檔案之後,剩餘的數量

leave = (int)streamTotal % MAX_BYTE;

//檔案的容量大於60Mb時進入迴圈

if (streamNum > 0) {

for(int i = 0; i < streamNum; ++i){

inOutb = new byte[MAX_BYTE];

//讀入流,儲存在byte陣列

inStream.read(inOutb, 0, MAX_BYTE);

outStream.write(inOutb);  //寫出流

outStream.flush();  //更新寫出的結果

}

}

//寫出剩下的流資料

inOutb = new byte[leave];

inStream.read(inOutb, 0, leave);

outStream.write(inOutb);

outStream.flush();

inStream.close();

outStream.close();

}

}

六、管道PipedInputStream/PipedOutputStream類:

當需要在兩個執行緒中讀寫資料的時候,由於執行緒的併發執行,讀寫的同步問題可能會發生困難,這時候可以使用管道,管道事實上是一個佇列。

管道是由系統維護的一個緩衝區,當然程式設計師也可以自己直接指定該緩衝區的大小(只需要設定管道流類中的PIPE_SIZE屬性的值)。當生產者生產出資料後,只需要將資料寫入管道中,消費者只需要從管道中讀取所需要的資料。利用管道的這種機制,可以將一個執行緒的輸出結果直接連線到另一個執行緒的輸入埠,實現兩者之間的資料直接傳送。

執行緒1
執行緒2
臨時檔案
管道

1.管道的連線:

方法之一是通過建構函式直接將某一個程式的輸出作為另一個程式的輸入,在定義物件時指明目標管道物件

PipedInputStream pInput=new PipedInputStream();

PipedOutputStream pOutput= new PipedOutputStream(pInput);

方法之二是利用雙方類中的任一個成員函式 connect()相連線

PipedInputStream pInput=new PipedInputStream();

PipedOutputStream pOutput= new PipedOutputStream();

pinput.connect(pOutput);

2.管道的輸入與輸出:

輸出管道物件呼叫write()成員函式輸出資料(即向管道的輸入端傳送資料);而輸入管道物件呼叫read()成員函式可以讀起資料(即從輸出管道中獲得資料)。這主要是藉助系統所提供的緩衝機制來實現的。

例項:Java的管道的輸入與輸出

import java.io.*;

public class PipedIO //程式執行後將sendFile檔案的內容拷貝到receiverFile檔案中

{

public static void main(String args[])

{

try

{

//構造讀寫的管道流物件

PipedInputStream pis=new PipedInputStream();

PipedOutputStream pos=new PipedOutputStream();

//實現關聯

pos.connect(pis);

//構造兩個執行緒,並且啟動。

new Sender(pos,"c:\\text2.txt").start();

new Receiver(pis,"c:\\text3.txt").start();

}

catch(IOException e)

{

System.out.println("Pipe Error"+ e);

}

}

}

//執行緒傳送

class Sender extends Thread

{

PipedOutputStream pos;

File file;

//構造方法

Sender(PipedOutputStream pos, String fileName)

{

this.pos=pos;

file=new File(fileName);

}

//執行緒執行方法

public void run()

{

try

{

//讀檔案內容

FileInputStream fs=new FileInputStream(file);

int data;

while((data=fs.read())!=-1)

{

//寫入管道始端

pos.write(data);

}

pos.close();

}

catch(IOException e)

{

System.out.println("Sender Error" +e);

}

}

}

//執行緒讀

class Receiver extends Thread

{

PipedInputStream pis;

File file;

//構造方法

Receiver(PipedInputStream pis, String fileName)

{

this.pis=pis;

file=new File(fileName);

}

//執行緒執行

public void run()

{

try

{

//寫檔案流物件

FileOutputStream fs=new FileOutputStream(file);

int data;

//從管道末端讀

while((data=pis.read())!=-1)

{

//寫入本地檔案

fs.write(data);

}

pis.close();

}

catch(IOException e)

{

System.out.println("Receiver Error" +e);

}

}

}

七、隨機檔案讀寫:RandomAccessFile類

它直接繼承於Object類而非InputStream/OutputStream類,從而可以實現讀寫檔案中任何位置中的資料(只需要改變檔案的讀寫位置的指標)。

程式設計步驟:

① 生成流物件並且指明讀寫型別;

② 移動讀寫位置;

③ 讀寫檔案內容;

④ 關閉檔案。

另外由於RandomAccessFile類實現了DataOutput與DataInput介面,因而利用它可以讀寫Java中的不同型別的基本型別資料(比如採用readLong()方法讀取長整數,而利用readInt()方法可以讀出整數值等)。

程式例項:

利用隨機資料流RandomAccessFile類來實現記錄使用者在鍵盤的輸入,每執行一次,將使用者的鍵盤輸入儲存在指定的UserInput.txt檔案中。

import java.io.*;

public class RandomFileRW

{

public static void main(String args[])

{

StringBuffer buf=new StringBuffer();

char ch;

try

{

while( (ch=(char)System.in.read()) !='\n')

{

buf.append(ch);

}

//讀寫方式可以為"r" or "rw"

RandomAccessFile myFileStream=new RandomAccessFile("c:\\UserInput.txt","rw");

myFileStream.seek(myFileStream.length()) ;

myFileStream.writeBytes(buf.toString());

//將使用者從鍵盤輸入的內容新增到檔案的尾部

myFileStream.close();

}

catch(IOException e)

{

}

}

}

八、DataInput/DataOutput介面:

實現與機器無關的各種資料格式讀寫(如readChar() 、readInt()、readLong()、readFloat(),而readLine()將返回一個String)。其中RandomAccessFile類實現了該介面,具有比FileInputStream或FileOutputStream類更靈活的資料讀寫方式。