1. 程式人生 > >儘量避免諸如x.read(new FileInputStream(sourceFile)); 的寫法

儘量避免諸如x.read(new FileInputStream(sourceFile)); 的寫法

      一不小心,順手寫了x.read(new FileInputStream(sourceFile)); 這樣的程式碼,卻引得自己花費了半個多小時去除錯問題。
     原因是這樣的:在開發某一個feature的時候,需要對操作的檔案進行backup,於是寫了諸如下面的程式碼(以下僅是演示程式碼,與實際要簡易,僅供參考):

/*
 * XXX是一個處理類,soureFile是一個輸入的File object
 
*/

XXX x 
=new XXX();
x.read(
new FileInputStream(sourceFile));
..... 
//complex logic process
String sourceFilePath 
= sourceFile.getPath();
int maxBackups =3;

List
<File> files =new ArrayList<File>();
files.add(traFile);
String base 
= sourceFile.getPath() +'.';
for (int generations =1true; generations++) {
    File f 
=new File(base + generations);
    files.add(f);
    
if (!f.exists()) {
        
break;
    }
}

int
 generations = files.size();
for (int generation = generations -1; generation >0; generation--) {
    
if (generation > maxBackups) {
        files.get(generation).delete();
    } 
else {
        
if(files.get(generation).exists()) files.get(generation).delete();
        files.get(generation 
-1).renameTo(files.get(generation));

    }
}

..... 
//complex logic processx.write(new FileOutputStream(sourceFilePath));

當寫完以後,執行TestCase並不是每次都成功,有時候就可以正確生成backup檔案,而有時候則沒有生成(沒有生成的概率大很多)。跟蹤了一下,發現當沒有正確生成backup的時候,是那段file renameTo沒有執行成功。就是如上面程式碼中“粗粉紅色的標記的”:files.get(generation - 1).renameTo(files.get(generation))

然後進行Debug狀態的step by step執行,卻每次都成功了。
仔細了想了想,可能的原因是 files.get(generation - 1) 這個所引物件的物件,在執行renameTo操作的時候,可能還在被某個資源鎖定,而沒有釋放。

帶著個這個想法,把程式碼從頭再過了一遍,終於發現是 x.read(new FileInputStream(sourceFile)); 這段出了問題。因為XXX這個類,在內部處理過程中,並沒有對輸入的inputstream進行關閉(當然,這是一個正確的設計和實現,一般我們在開發過程中,都不會在“使用者”內部關閉外部的流,這樣危險性非常大)。

但是,為了程式碼了簡潔,很隨意的就進行了 x.read(new FileInputStream(sourceFile));  這樣的書寫

正是這樣的書寫,讓後面針對soureFile的操作不能執行成功。因為所用在這個soureFile上的InputStream流並沒有被“真正關閉”。

於是改成:
InputStream is = new FileInputStream(sourceFile);
x.read(is);
is.close;
就可以了。

當然,並不是說諸如 x.read(new FileInputStream(sourceFile));  的寫法不能用,而是儘量避免在“在同一個方法開閉區間內多次引用sourceFile”,在這樣場合下,就肯定不能用了。