我們都知道在電腦上對數據的存儲有三種方式,一種是外存,一種是內存,一種是緩存。比如電腦上的硬盤,磁盤,U盤等都是外存,在電腦上有內存條,緩存是在CPU裡面的。外存的存儲量最大,其次是內存,最後是緩存,但是外存的數據的讀取最慢,其次是內存,緩存最快。這裡總結從外存讀取數據到內存以及將數據從內存寫到外存中。對於內存和外存的理解,我們可以簡單的理解為容器,即外存是一個容器,內存又是另外一個容器。那又怎樣把放在外存這個容器內的數據讀取到內存這個容器以及怎麼把內存這個容器裡的數據存到外存中呢?在Java中提供瞭輸入輸出相關的類,這些類在java.io包中,java中將輸入輸出抽象稱為流,就好像水管,將兩個容器連接起來。將數據沖外存中讀取到內存中的稱為輸入流,將數據從內存寫入外存中的稱為輸出流。在次以文件輸入流和文件輸出流為例說明數據的讀取和寫入的操作。
查閱API文檔可知,文件輸入流FileInputStream隻有一個構造器FilterInputStream(InputStream in),它傳入一個InputStream類型的參數。知道瞭構造方法,就可以實例化一個FileInputStream類的對象。要將數據從硬盤上讀取到內存中,首先要定義一個FileTest類,再定義一個方法readFile(),給該方法傳入一個要讀取某個文件路徑的字符串形參,最後返回一個字符串值。在方法中首先需要一個FileInputStream類的對象,所以要實例化一個FileInputStream類的對象:java.io.FileInputStream fis = new java.io.FileInputStream(path);在實例化對象時會提示有異常錯誤,這裡先不討論異常機制,就按固定的格式:try{ }catch(Exception ct){ct.printStackTrace();}處理就行瞭。創建對象之後就可以用該類的方法對數據讀取瞭。首先要讀取文件的長度,可以用方法available(),然後讀取文件中的數據,可以用read()讀取,該方法隻能一個字節一個字節的讀取數據。最後要實例化一個byte數組,它的作用是將讀取到的數據保存到數組中,還需要一個whlie循環將所有數據讀取到數組中,還需要註意的是read()方法當讀取完最後一個字節,在讀取一遍時,這時返回的結果是-1。最後讀取完之後別忘瞭用close()方法將輸入流關閉。具體代碼如下:
/**
* 讀入給定路徑文件的數據
* @param path:給定的路徑
* @return:返回字符串類型的數據
*/
public String readFile(String path){
try{
//創建文件輸入流對象
java.io.FileInputStream fis = new java.io.FileInputStream(path);
//獲取文件的長度
int len = fis.available();
//根據文件的長度創建一個字節數組,保存從文件讀取到的數據
byte[] bt = new byte[len];
//讀入一個字節
int bj = fis.read();
int i=0;
while (bj!=-1){
//將讀取的字節放入到數組中
bt[i]=(byte)bj;
//繼續讀取下一個字節
bj = fis.read();
i++;
}
要把數據從內存中寫入到外存中的指定的文件裡的方法和上面的方法差不多。與之對應的有一個FileOutputStream類,該類有五個構造方法,這裡使用FileOutputStream(String name)這個構造方法實例化一個對象。首先要定義一個writeFile()方法,再給該方法傳入指定的文件路徑和要寫出的數據的兩個字符串形參。然後實例化一個java.io.FileOutputStream fs = new java.io.FileOutputStream(path);跟上面一樣也會報出異常錯誤,處理方法和上面是一樣的。再將要寫出的字符串前要先把字符串轉化為字節數組,在String類中有一個方法getBytes()
可以將字符串轉化為字節數組。然後要遍歷得到的字節數組,將字節數組中的每個元素依次寫出。最後別忘瞭要用fs.flush();和fs.close()兩個方法分別將輸出流中的字節強制輸出和關閉輸出流。具體代碼如下:
/**
* 將數據寫入指定文件
* @param path:指定的文件
* @param content:寫入的數據
*/
public void writeFile(String path,String content){
try{
//創建輸出流對象
java.io.FileOutputStream fs = new java.io.FileOutputStream(path);
//將字符串轉成字節數組
byte[] b = content.getBytes();
//遍歷數組
for (int i=0;i<b.length;i++){
//寫入數據
fs.write(b[i]);
}
//強制寫出輸出流中所有字節
fs.flush();
//關閉流
fs.close();
}catch(Exception et){
et.printStackTrace();
}
}
上面兩個方法寫完之後,先調用第一個方法在調用第二個方法就可以完成文件的復制。但是這種復制存在兩個問題,第一是復制的速度太慢,第二是有些文件復制之後是亂碼,不能查看。要解決這兩個問題,首先要分析上面兩個方法的執行過程,看到第一個方法用到瞭數組,第二個方法要把字符串轉化為字節數組。所以可以考慮不要用數組,並且不要把字符串轉化為字節數組。所以要一邊讀入數據一邊寫出數據,這樣不僅把前面的兩個問題解決瞭,而且代碼還簡潔瞭不少,具體代碼如下所示:
/**
* 文件復制的方法
* @param srcPath
* @param destPath
* @return
*/
public boolean copyFile(String srcPath, String destPath) {
try{
//創建輸入流對象
java.io.FileInputStream fis = new java.io.FileInputStream(srcPath);
//創建輸出流對象
java.io.FileOutputStream fos = new java.io.FileOutputStream(destPath);
//讀入一個字節的數據
int rd = fis.read();
while (rd!=-1){
//將內存中的數據寫到硬盤的文件
fos.write(rd);
//繼續讀入數據
rd = fis.read();
}
//關閉輸入流
fis.close();
//強制寫出輸出流中剩餘數據
fos.flush();
//關閉輸出流
fos.close();
return true;
}catch(Exception ct){
ct.printStackTrace();
}
return false;
}
經過上面的代碼的修改之後,復制文件基本沒有問題,但是當復制比較大的文件時速度還是很慢,這時就需要輸入輸出緩沖流,他們分別是BufferedInputStream和BufferedOutputStream。
他們的使用入一下代碼所示:
/**
* 文件復制的方法
*
* @param srcPath
* @param destPath
* @return
*/
public boolean copyFile(String srcPath, String destPath) {
try{
//創建輸入流對象
java.io.FileInputStream fis = new java.io.FileInputStream(srcPath);
//創建輸出流對象
java.io.FileOutputStream fos = new java.io.FileOutputStream(destPath);
//創建輸入緩沖流
java.io.BufferedInputStream bis = new java.io.BufferedInputStream(fis);
//創建輸出緩沖流
java.io.BufferedOutputStream bos = new java.io.BufferedOutputStream(fos);
//讀入一個字節的數據
int rd = bis.read();
while (rd!=-1){
//將內存中的數據寫到硬盤的文件
bos.write(rd);
//繼續讀入數據
rd = bis.read();
}
//關閉輸入流
fis.close();
//強制寫出輸出流中剩餘數據
fos.flush();
//關閉輸出流
fos.close();
return true;
}catch(Exception ct){
ct.printStackTrace();
}
return false;
}